abstractionkit
Version:
Account Abstraction 4337 SDK by Candidelabs
1 lines • 946 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":["signHash","ecdsaSignHash","signHash","signHash","signHash","signHash","UINT256_MAX","TOKEN_APPROVE_AMOUNT_MULTIPLIER","TOKENS_REQUIRING_ALLOWANCE_RESET","signHash"],"sources":["../src/ethereUtils.ts","../src/errors.ts","../src/transport/Transport.ts","../src/transport/BaseRpcTransport.ts","../src/transport/HttpTransport.ts","../src/types.ts","../src/transport/normalize.ts","../src/transport/JsonRpcNode.ts","../src/Bundler.ts","../src/constants.ts","../src/signer/negotiate.ts","../src/utils7702.ts","../src/utils.ts","../src/account/SendUseroperationResponse.ts","../src/account/SmartAccount.ts","../src/account/Calibur/types.ts","../src/account/Calibur/Calibur7702Account.ts","../src/factory/SmartAccountFactory.ts","../src/factory/SafeAccountFactory.ts","../src/utilsTenderly.ts","../src/account/Safe/multisend.ts","../src/account/Safe/safeMessage.ts","../src/account/Safe/types.ts","../src/account/Safe/SafeAccount.ts","../src/account/Safe/modules/SafeModule.ts","../src/account/Safe/modules/AllowanceModule.ts","../src/account/Safe/modules/SocialRecoveryModule.ts","../src/account/Safe/constants.ts","../src/account/Safe/MerkleTree.ts","../src/account/Safe/SafeMultiChainSigAccount.ts","../src/account/Safe/SafeAccountV0_3_0.ts","../src/account/Safe/SafeAccountV0_2_0.ts","../src/account/Safe/SafeAccountV1_5_0_M_0_3_0.ts","../src/account/simple/Simple7702Account.ts","../src/account/simple/Simple7702AccountV09.ts","../src/paymaster/Paymaster.ts","../src/paymaster/AllowAllPaymaster.ts","../src/paymaster/CandidePaymaster.ts","../src/paymaster/Erc7677Paymaster.ts","../src/paymaster/WorldIdPermissionlessPaymaster.ts","../src/account/Safe/adapters.ts","../src/signer/adapters.ts","../src/userOperationRevert.ts","../src/abstractionkit.ts"],"sourcesContent":["/**\n * ethereUtils — copying related code from ethers v6 with some modification,\n * covering exactly the surface area used by `abstractionkit`.\n *\n * Sources (ethers v6.13.x):\n * src.ts/utils/{data,maths,utf8,rlp-encode}.ts\n * src.ts/crypto/{keccak,signing-key,signature}.ts\n * src.ts/hash/{id,message,solidity,typed-data}.ts\n * src.ts/address/{address,checks}.ts\n * src.ts/abi/{abi-coder, coders/*}.ts\n * src.ts/transaction/address.ts\n */\n\nimport { keccak_256 } from \"@noble/hashes/sha3\";\nimport { secp256k1 } from \"@noble/curves/secp256k1\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type Hex = `0x${string}`;\nexport type BytesLike = string | Uint8Array;\nexport type Numeric = number | bigint;\nexport type BigNumberish = string | Numeric;\nexport type RlpStructuredDataish = BytesLike | ReadonlyArray<RlpStructuredDataish>;\n\nexport interface TypedDataDomain {\n name?: null | string;\n version?: null | string;\n chainId?: null | BigNumberish;\n verifyingContract?: null | string;\n salt?: null | BytesLike;\n}\n\nexport interface TypedDataField {\n name: string;\n type: string;\n}\n\nexport interface Signature {\n r: Hex;\n s: Hex;\n v: 27 | 28;\n yParity: 0 | 1;\n /** 65-byte hex: `r (32) || s (32) || v (1)`. */\n serialized: Hex;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Errors (simplified)\n// ethers ships a rich error system; we keep the assertion shape and message\n// formatting but drop the typed-error machinery (CALL_EXCEPTION,\n// BUFFER_OVERRUN, NUMERIC_FAULT, …) since none of abstractionkit's call\n// sites discriminate on them.\n// ─────────────────────────────────────────────────────────────────────────────\n\n// Format an argument value for inclusion in an error message without leaking\n// secrets. Private keys, digests, and calldata flow through `getBytes` and\n// can land here on malformed input, so:\n// 1. If the parameter name hints at a secret, fully redact.\n// 2. Hex strings get a prefix/suffix preview (callers can recognize the\n// value in logs without copying the whole thing into a bug report).\n// 3. Any string long enough to be a key but missed by (1) and (2) is\n// redacted by length, as defense-in-depth.\n// 4. Uint8Array is never echoed (a raw private key can flow this way too).\nfunction redactArgumentValue(name: string, value: unknown): string {\n if (value === null || value === undefined) return String(value);\n if (typeof value === \"string\") {\n const n = name.toLowerCase();\n if (\n n.includes(\"key\") ||\n n.includes(\"secret\") ||\n n.includes(\"token\") ||\n n.includes(\"password\") ||\n n.includes(\"mnemonic\")\n ) {\n return \"[REDACTED]\";\n }\n if (/^0x[0-9a-f]+$/i.test(value) && value.length > 18) {\n return `${value.slice(0, 10)}…${value.slice(-6)}`;\n }\n if (value.length > 64) return `[REDACTED string length=${value.length}]`;\n return value;\n }\n if (typeof value === \"number\" || typeof value === \"boolean\" || typeof value === \"bigint\") {\n return String(value);\n }\n if (value instanceof Uint8Array) return `[REDACTED Uint8Array length=${value.length}]`;\n return `[REDACTED ${typeof value}]`;\n}\n\nfunction assertArgument(check: unknown, message: string, name: string, value: unknown): asserts check {\n if (!check) throw new Error(`invalid argument (${name}=${redactArgumentValue(name, value)}, message=${message})`);\n}\nfunction assertCheck(check: unknown, message: string): asserts check {\n if (!check) throw new Error(message);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Data helpers (src.ts/utils/data.ts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst HexCharacters = \"0123456789abcdef\";\n\nfunction _getBytes(value: BytesLike, name?: string, copy?: boolean): Uint8Array {\n if (value instanceof Uint8Array) {\n return copy ? new Uint8Array(value) : value;\n }\n if (typeof value === \"string\" && value.length % 2 === 0 && value.match(/^0x[0-9a-f]*$/i)) {\n const result = new Uint8Array((value.length - 2) / 2);\n let offset = 2;\n for (let i = 0; i < result.length; i++) {\n result[i] = parseInt(value.substring(offset, offset + 2), 16);\n offset += 2;\n }\n return result;\n }\n assertArgument(false, \"invalid BytesLike value\", name || \"value\", value);\n}\n\nexport function getBytes(value: BytesLike, name?: string): Uint8Array {\n return _getBytes(value, name, false);\n}\n\nfunction getBytesCopy(value: BytesLike, name?: string): Uint8Array {\n return _getBytes(value, name, true);\n}\n\nexport function isHexString(value: unknown, length?: number | boolean): value is `0x${string}` {\n if (typeof value !== \"string\" || !value.match(/^0x[0-9A-Fa-f]*$/)) return false;\n if (typeof length === \"number\" && value.length !== 2 + 2 * length) return false;\n if (length === true && value.length % 2 !== 0) return false;\n return true;\n}\n\nexport function hexlify(data: BytesLike): Hex {\n const bytes = getBytes(data);\n let result = \"0x\";\n for (let i = 0; i < bytes.length; i++) {\n const v = bytes[i];\n result += HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f];\n }\n return result as Hex;\n}\n\nexport function concat(datas: ReadonlyArray<BytesLike>): Hex {\n return (\"0x\" + datas.map((d) => hexlify(d).substring(2)).join(\"\")) as Hex;\n}\n\nexport function dataLength(data: BytesLike): number {\n if (isHexString(data, true)) return (data.length - 2) / 2;\n return getBytes(data).length;\n}\n\nfunction zeroPad(data: BytesLike, length: number, left: boolean): Hex {\n const bytes = getBytes(data);\n assertCheck(length >= bytes.length, \"padding exceeds data length\");\n const result = new Uint8Array(length);\n result.fill(0);\n if (left) result.set(bytes, length - bytes.length);\n else result.set(bytes, 0);\n return hexlify(result);\n}\n\nfunction zeroPadValue(data: BytesLike, length: number): Hex {\n return zeroPad(data, length, true);\n}\n\nfunction zeroPadBytes(data: BytesLike, length: number): Hex {\n return zeroPad(data, length, false);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Math helpers (src.ts/utils/maths.ts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst BN_0 = 0n;\nconst BN_1 = 1n;\nconst maxValue = 0x1fffffffffffff; // 2^53 - 1 (IEEE 754 mantissa)\n\nfunction getBigInt(value: BigNumberish, name?: string): bigint {\n switch (typeof value) {\n case \"bigint\": return value;\n case \"number\":\n assertArgument(Number.isInteger(value), \"underflow\", name || \"value\", value);\n assertArgument(value >= -maxValue && value <= maxValue, \"overflow\", name || \"value\", value);\n return BigInt(value);\n case \"string\":\n try {\n if (value === \"\") throw new Error(\"empty string\");\n if (value[0] === \"-\" && value[1] !== \"-\") return -BigInt(value.substring(1));\n return BigInt(value);\n } catch (e) {\n assertArgument(false, `invalid BigNumberish string: ${(e as Error).message}`, name || \"value\", value);\n }\n }\n assertArgument(false, \"invalid BigNumberish value\", name || \"value\", value);\n}\n\nfunction getUint(value: BigNumberish, name?: string): bigint {\n const result = getBigInt(value, name);\n assertCheck(result >= BN_0, \"unsigned value cannot be negative\");\n return result;\n}\n\nfunction getNumber(value: BigNumberish, name?: string): number {\n switch (typeof value) {\n case \"bigint\":\n assertArgument(value >= -maxValue && value <= maxValue, \"overflow\", name || \"value\", value);\n return Number(value);\n case \"number\":\n assertArgument(Number.isInteger(value), \"underflow\", name || \"value\", value);\n assertArgument(value >= -maxValue && value <= maxValue, \"overflow\", name || \"value\", value);\n return value;\n case \"string\":\n try {\n if (value === \"\") throw new Error(\"empty string\");\n return getNumber(BigInt(value), name);\n } catch (e) {\n assertArgument(false, `invalid numeric string: ${(e as Error).message}`, name || \"value\", value);\n }\n }\n assertArgument(false, \"invalid numeric value\", name || \"value\", value);\n}\n\nconst Nibbles = \"0123456789abcdef\";\n\nfunction toBigInt(value: BigNumberish | Uint8Array): bigint {\n if (value instanceof Uint8Array) {\n let result = \"0x0\";\n for (const v of value) {\n result += Nibbles[v >> 4];\n result += Nibbles[v & 0x0f];\n }\n return BigInt(result);\n }\n return getBigInt(value);\n}\n\nfunction toNumber(value: BigNumberish | Uint8Array): number {\n return getNumber(toBigInt(value));\n}\n\nfunction mask(_value: BigNumberish, _bits: Numeric): bigint {\n const value = getUint(_value, \"value\");\n const bits = BigInt(getNumber(_bits, \"bits\"));\n return value & ((BN_1 << bits) - BN_1);\n}\n\nfunction toTwos(_value: BigNumberish, _width: Numeric): bigint {\n let value = getBigInt(_value, \"value\");\n const width = BigInt(getNumber(_width, \"width\"));\n const limit = BN_1 << (width - BN_1);\n if (value < BN_0) {\n value = -value;\n assertCheck(value <= limit, \"toTwos: too low\");\n const m = (BN_1 << width) - BN_1;\n return ((~value) & m) + BN_1;\n }\n assertCheck(value < limit, \"toTwos: too high\");\n return value;\n}\n\nfunction fromTwos(_value: BigNumberish, _width: Numeric): bigint {\n const value = getUint(_value, \"value\");\n const width = BigInt(getNumber(_width, \"width\"));\n assertCheck((value >> width) === BN_0, \"fromTwos: overflow\");\n if (value >> (width - BN_1)) {\n const m = (BN_1 << width) - BN_1;\n return -(((~value) & m) + BN_1);\n }\n return value;\n}\n\nfunction toBeHex(_value: BigNumberish, _width?: Numeric): Hex {\n const value = getUint(_value, \"value\");\n let result = value.toString(16);\n if (_width == null) {\n if (result.length % 2) result = \"0\" + result;\n } else {\n const width = getNumber(_width, \"width\");\n if (width === 0 && value === BN_0) return \"0x\" as Hex;\n assertCheck(width * 2 >= result.length, `value exceeds width (${width} bytes)`);\n while (result.length < width * 2) result = \"0\" + result;\n }\n return (\"0x\" + result) as Hex;\n}\n\nexport function toBeArray(_value: BigNumberish, _width?: Numeric): Uint8Array {\n const value = getUint(_value, \"value\");\n if (value === BN_0) {\n const width = _width != null ? getNumber(_width, \"width\") : 0;\n return new Uint8Array(width);\n }\n let hex = value.toString(16);\n if (hex.length % 2) hex = \"0\" + hex;\n if (_width != null) {\n const width = getNumber(_width, \"width\");\n while (hex.length < width * 2) hex = \"00\" + hex;\n assertCheck(width * 2 === hex.length, `value exceeds width (${width} bytes)`);\n }\n const result = new Uint8Array(hex.length / 2);\n for (let i = 0; i < result.length; i++) {\n const offset = i * 2;\n result[i] = parseInt(hex.substring(offset, offset + 2), 16);\n }\n return result;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// UTF-8 (src.ts/utils/utf8.ts — encoding + decoding)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function toUtf8Bytes(str: string): Uint8Array {\n assertArgument(typeof str === \"string\", \"invalid string value\", \"str\", str);\n const result: number[] = [];\n for (let i = 0; i < str.length; i++) {\n const c = str.charCodeAt(i);\n if (c < 0x80) {\n result.push(c);\n } else if (c < 0x800) {\n result.push((c >> 6) | 0xc0);\n result.push((c & 0x3f) | 0x80);\n } else if ((c & 0xfc00) === 0xd800) {\n i++;\n const c2 = str.charCodeAt(i);\n assertArgument(i < str.length && (c2 & 0xfc00) === 0xdc00, \"invalid surrogate pair\", \"str\", str);\n const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);\n result.push((pair >> 18) | 0xf0);\n result.push(((pair >> 12) & 0x3f) | 0x80);\n result.push(((pair >> 6) & 0x3f) | 0x80);\n result.push((pair & 0x3f) | 0x80);\n } else {\n result.push((c >> 12) | 0xe0);\n result.push(((c >> 6) & 0x3f) | 0x80);\n result.push((c & 0x3f) | 0x80);\n }\n }\n return new Uint8Array(result);\n}\n\n/**\n * Decode UTF-8 bytes to a string. Pure JS so it works in every runtime,\n * including React Native / Hermes where `TextDecoder` is not defined by default.\n *\n * Throws on bad prefix, truncated sequences, missing or unexpected continuation bytes,\n * overlong encodings, surrogate code points (U+D800..U+DFFF), and code\n * points above U+10FFFF. For ABI string payloads this is the right policy —\n * well-formed contracts never emit broken UTF-8, so an error signals a\n * real problem rather than silently corrupting the decoded value.\n *\n * @throws Error when `bytes` is not a valid UTF-8 sequence.\n */\nexport function fromUtf8Bytes(bytes: Uint8Array): string {\n const codepoints: number[] = [];\n let i = 0;\n while (i < bytes.length) {\n const c = bytes[i++];\n\n // 1-byte ASCII.\n if ((c & 0x80) === 0) {\n codepoints.push(c);\n continue;\n }\n\n // Lead-byte classification per RFC 3629. Bytes 0xf8..0xff are not\n // valid UTF-8 lead bytes and fall through to the error branch.\n let extraLength: number;\n let overlongMask: number;\n if ((c & 0xe0) === 0xc0) {\n extraLength = 1;\n overlongMask = 0x7f;\n } else if ((c & 0xf0) === 0xe0) {\n extraLength = 2;\n overlongMask = 0x7ff;\n } else if ((c & 0xf8) === 0xf0) {\n extraLength = 3;\n overlongMask = 0xffff;\n } else {\n const kind = (c & 0xc0) === 0x80 ? \"unexpected continuation\" : \"bad prefix\";\n throw new Error(`invalid UTF-8: ${kind} byte 0x${c.toString(16)} at index ${i - 1}`);\n }\n\n if (i + extraLength > bytes.length) {\n throw new Error(`invalid UTF-8: truncated sequence at index ${i - 1}`);\n }\n\n let res = c & ((1 << (8 - extraLength - 1)) - 1);\n for (let j = 0; j < extraLength; j++) {\n const next = bytes[i++];\n if ((next & 0xc0) !== 0x80) {\n throw new Error(\n `invalid UTF-8: missing continuation byte 0x${next.toString(16)} at index ${i - 1}`,\n );\n }\n res = (res << 6) | (next & 0x3f);\n }\n\n if (res <= overlongMask) {\n throw new Error(`invalid UTF-8: overlong encoding of U+${res.toString(16).toUpperCase()}`);\n }\n if (res >= 0xd800 && res <= 0xdfff) {\n throw new Error(`invalid UTF-8: surrogate code point U+${res.toString(16).toUpperCase()}`);\n }\n if (res > 0x10ffff) {\n throw new Error(`invalid UTF-8: code point U+${res.toString(16).toUpperCase()} out of range`);\n }\n\n codepoints.push(res);\n }\n\n let result = \"\";\n for (const cp of codepoints) result += String.fromCodePoint(cp);\n return result;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Crypto: keccak256 (src.ts/crypto/keccak.ts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function keccak256(_data: BytesLike): Hex {\n const data = getBytes(_data, \"data\");\n return hexlify(keccak_256(data));\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Hash: id, hashMessage (src.ts/hash/{id,message}.ts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function id(value: string): Hex {\n return keccak256(toUtf8Bytes(value));\n}\n\nconst MessagePrefix = \"\\x19Ethereum Signed Message:\\n\";\n\nexport function hashMessage(message: Uint8Array | string): Hex {\n if (typeof message === \"string\") message = toUtf8Bytes(message);\n return keccak256(concat([\n toUtf8Bytes(MessagePrefix),\n toUtf8Bytes(String(message.length)),\n message,\n ]));\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Address: getAddress, isAddress (src.ts/address/{address,checks}.ts)\n// ICAP/Base36 dropped — abstractionkit never passes ICAP addresses.\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction getChecksumAddress(address: string): Hex {\n address = address.toLowerCase();\n const chars = address.substring(2).split(\"\");\n const expanded = new Uint8Array(40);\n for (let i = 0; i < 40; i++) expanded[i] = chars[i].charCodeAt(0);\n const hashed = getBytes(keccak256(expanded));\n for (let i = 0; i < 40; i += 2) {\n if ((hashed[i >> 1] >> 4) >= 8) chars[i] = chars[i].toUpperCase();\n if ((hashed[i >> 1] & 0x0f) >= 8) chars[i + 1] = chars[i + 1].toUpperCase();\n }\n return (\"0x\" + chars.join(\"\")) as Hex;\n}\n\nexport function getAddress(address: string): Hex {\n assertArgument(typeof address === \"string\", \"invalid address\", \"address\", address);\n if (address.match(/^(0x)?[0-9a-fA-F]{40}$/)) {\n if (!address.startsWith(\"0x\")) address = \"0x\" + address;\n const result = getChecksumAddress(address);\n assertArgument(\n !address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) || result === address,\n \"bad address checksum\", \"address\", address,\n );\n return result;\n }\n assertArgument(false, \"invalid address\", \"address\", address);\n}\n\nexport function isAddress(value: unknown): value is string {\n try {\n getAddress(value as string);\n return true;\n } catch {\n return false;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Solidity packed (src.ts/hash/solidity.ts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst regexBytes = /^bytes([0-9]+)$/;\nconst regexNumber = /^(u?int)([0-9]*)$/;\nconst regexArray = /^(.*)\\[([0-9]*)\\]$/;\n\nfunction _pack(type: string, value: unknown, isArray?: boolean): Uint8Array {\n switch (type) {\n case \"address\":\n if (isArray) return getBytes(zeroPadValue(value as string, 32));\n return getBytes(getAddress(value as string));\n case \"string\":\n return toUtf8Bytes(value as string);\n case \"bytes\":\n return getBytes(value as BytesLike);\n case \"bool\": {\n const v: Hex = value ? \"0x01\" : \"0x00\";\n if (isArray) return getBytes(zeroPadValue(v, 32));\n return getBytes(v);\n }\n }\n\n let match = type.match(regexNumber);\n if (match) {\n const signed = match[1] === \"int\";\n let size = parseInt(match[2] || \"256\");\n assertArgument(\n (!match[2] || match[2] === String(size)) && size % 8 === 0 && size !== 0 && size <= 256,\n \"invalid number type\", \"type\", type,\n );\n if (isArray) size = 256;\n const v = signed ? toTwos(value as BigNumberish, size) : (value as BigNumberish);\n return getBytes(zeroPadValue(toBeArray(v), size / 8));\n }\n\n match = type.match(regexBytes);\n if (match) {\n const size = parseInt(match[1]);\n assertArgument(String(size) === match[1] && size !== 0 && size <= 32, \"invalid bytes type\", \"type\", type);\n assertArgument(dataLength(value as BytesLike) === size, `invalid value for ${type}`, \"value\", value);\n if (isArray) return getBytes(zeroPadBytes(value as BytesLike, 32));\n return getBytes(value as BytesLike);\n }\n\n match = type.match(regexArray);\n if (match && Array.isArray(value)) {\n const baseType = match[1];\n const count = parseInt(match[2] || String(value.length));\n assertArgument(count === value.length, `invalid array length for ${type}`, \"value\", value);\n const result: Uint8Array[] = [];\n for (const v of value) result.push(_pack(baseType, v, true));\n return getBytes(concat(result));\n }\n\n assertArgument(false, \"invalid type\", \"type\", type);\n}\n\nexport function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArray<unknown>): Hex {\n assertArgument(types.length === values.length, \"wrong number of values\", \"values\", values);\n const tight: Uint8Array[] = [];\n for (let i = 0; i < types.length; i++) {\n tight.push(_pack(types[i], values[i]));\n }\n return hexlify(concat(tight));\n}\n\nexport function solidityPackedKeccak256(types: ReadonlyArray<string>, values: ReadonlyArray<unknown>): Hex {\n return keccak256(solidityPacked(types, values));\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// RLP encode (src.ts/utils/rlp-encode.ts)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction arrayifyInteger(value: number): number[] {\n const result: number[] = [];\n while (value) {\n result.unshift(value & 0xff);\n value >>= 8;\n }\n return result;\n}\n\nfunction _rlpEncode(object: RlpStructuredDataish): number[] {\n if (Array.isArray(object)) {\n let payload: number[] = [];\n object.forEach((child) => {\n payload = payload.concat(_rlpEncode(child));\n });\n if (payload.length <= 55) {\n payload.unshift(0xc0 + payload.length);\n return payload;\n }\n const length = arrayifyInteger(payload.length);\n length.unshift(0xf7 + length.length);\n return length.concat(payload);\n }\n const data: number[] = Array.prototype.slice.call(getBytes(object as BytesLike, \"object\"));\n if (data.length === 1 && data[0] <= 0x7f) return data;\n if (data.length <= 55) {\n data.unshift(0x80 + data.length);\n return data;\n }\n const length = arrayifyInteger(data.length);\n length.unshift(0xb7 + length.length);\n return length.concat(data);\n}\n\nexport function encodeRlp(object: RlpStructuredDataish): Hex {\n let result = \"0x\";\n for (const v of _rlpEncode(object)) {\n result += Nibbles[v >> 4];\n result += Nibbles[v & 0xf];\n }\n return result as Hex;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ABI codec (src.ts/abi/* — class hierarchy collapsed into recursive functions)\n//\n// Type grammar (subset used by abstractionkit):\n// address | bool | string | bytes | bytes<1..32> | uint<8..256> | int<8..256>\n// T[] | T[<n>] | (T1,T2,...) (tuples)\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype AbiType =\n | { kind: \"uint\"; bits: number; signed: boolean }\n | { kind: \"address\" }\n | { kind: \"bool\" }\n | { kind: \"bytesN\"; size: number }\n | { kind: \"bytes\" }\n | { kind: \"string\" }\n | { kind: \"array\"; child: AbiType; size: number /* -1 = dynamic */ }\n | { kind: \"tuple\"; components: AbiType[] };\n\nfunction splitTopLevel(s: string): string[] {\n const out: string[] = [];\n let depth = 0, start = 0;\n for (let i = 0; i < s.length; i++) {\n const c = s[i];\n if (c === \"(\" || c === \"[\") depth++;\n else if (c === \")\" || c === \"]\") depth--;\n else if (c === \",\" && depth === 0) { out.push(s.slice(start, i)); start = i + 1; }\n }\n if (start < s.length) out.push(s.slice(start));\n return out.map((x) => x.trim()).filter((x) => x.length > 0);\n}\n\nfunction parseType(s: string): AbiType {\n s = s.trim();\n const m = s.match(/^(.+?)((?:\\[\\d*\\])*)$/);\n assertArgument(!!m, `invalid type`, \"type\", s);\n const base = m![1], suffix = m![2];\n\n let t: AbiType;\n if (base.startsWith(\"(\")) {\n assertArgument(base.endsWith(\")\"), `unbalanced tuple`, \"type\", s);\n t = { kind: \"tuple\", components: splitTopLevel(base.slice(1, -1)).map(parseType) };\n } else if (base === \"address\") t = { kind: \"address\" };\n else if (base === \"bool\") t = { kind: \"bool\" };\n else if (base === \"string\") t = { kind: \"string\" };\n else if (base === \"bytes\") t = { kind: \"bytes\" };\n else if (base === \"uint\" || base === \"int\") t = { kind: \"uint\", bits: 256, signed: base === \"int\" };\n else {\n const um = base.match(regexNumber);\n if (um) {\n const bits = parseInt(um[2] || \"256\");\n assertArgument(bits !== 0 && bits <= 256 && bits % 8 === 0, \"invalid number type\", \"type\", base);\n t = { kind: \"uint\", bits, signed: um[1] === \"int\" };\n } else {\n const bm = base.match(regexBytes);\n assertArgument(!!bm, `unknown type ${base}`, \"type\", base);\n const size = parseInt(bm![1]);\n assertArgument(size !== 0 && size <= 32, \"invalid bytes type\", \"type\", base);\n t = { kind: \"bytesN\", size };\n }\n }\n\n for (const ap of suffix.matchAll(/\\[(\\d*)\\]/g)) {\n t = { kind: \"array\", child: t, size: ap[1] ? parseInt(ap[1]) : -1 };\n }\n return t;\n}\n\nfunction isDynamic(t: AbiType): boolean {\n switch (t.kind) {\n case \"bytes\": case \"string\": return true;\n case \"array\": return t.size === -1 || isDynamic(t.child);\n case \"tuple\": return t.components.some(isDynamic);\n default: return false;\n }\n}\n\nfunction staticSize(t: AbiType): number {\n switch (t.kind) {\n case \"uint\": case \"address\": case \"bool\": case \"bytesN\": return 32;\n case \"array\": return t.size * staticSize(t.child);\n case \"tuple\": return t.components.reduce((s, c) => s + staticSize(c), 0);\n default: throw new Error(`staticSize: dynamic type ${t.kind}`);\n }\n}\n\nconst WordSize = 32;\nconst Padding = new Uint8Array(WordSize);\n// Allocation cap for dynamic arrays whose element type has zero head footprint\n// (e.g. empty tuples), where the payload carries no per-element bytes to bound\n// the length against. Far above any realistic decode, low enough to stay safe.\nconst MaxZeroFootprintArrayLen = 1 << 20;\n\nfunction padLeft(b: Uint8Array, size: number): Uint8Array {\n assertCheck(b.length <= size, \"padLeft: overflow\");\n const out = new Uint8Array(size);\n out.set(b, size - b.length);\n return out;\n}\n\nfunction padRight(b: Uint8Array, size: number): Uint8Array {\n assertCheck(b.length <= size, \"padRight: overflow\");\n const out = new Uint8Array(size);\n out.set(b, 0);\n return out;\n}\n\nfunction padTo32(len: number): number {\n return Math.ceil(len / WordSize) * WordSize;\n}\n\nconst BN_MAX_UINT256 = (1n << 256n) - 1n;\n\nfunction encodeValue(t: AbiType, v: unknown): Uint8Array {\n switch (t.kind) {\n case \"uint\": {\n let value = getBigInt(v as BigNumberish, \"value\");\n const maxUintValue = mask(BN_MAX_UINT256, WordSize * 8);\n if (t.signed) {\n const bounds = mask(maxUintValue, t.bits - 1);\n assertCheck(value <= bounds && value >= -(bounds + 1n), `int${t.bits}: value out-of-bounds`);\n value = toTwos(value, 8 * WordSize);\n } else {\n assertCheck(value >= 0n && value <= mask(maxUintValue, t.bits), `uint${t.bits}: out-of-bounds`);\n }\n return padLeft(toBeArray(value), WordSize);\n }\n case \"address\": {\n const bytes = getBytes(getAddress(v as string));\n return padLeft(bytes, WordSize);\n }\n case \"bool\":\n return padLeft(new Uint8Array([v ? 1 : 0]), WordSize);\n case \"bytesN\": {\n const bytes = getBytes(v as BytesLike);\n assertCheck(bytes.length === t.size, `bytes${t.size}: wrong length`);\n return padRight(bytes, WordSize);\n }\n case \"bytes\": {\n const bytes = getBytes(v as BytesLike);\n return concatBytes([padLeft(toBeArray(bytes.length), WordSize), padRight(bytes, padTo32(bytes.length))]);\n }\n case \"string\": {\n const bytes = toUtf8Bytes(v as string);\n return concatBytes([padLeft(toBeArray(bytes.length), WordSize), padRight(bytes, padTo32(bytes.length))]);\n }\n case \"array\": {\n const arr = v as unknown[];\n assertCheck(t.size === -1 || arr.length === t.size, \"array: length mismatch\");\n const types = Array<AbiType>(arr.length).fill(t.child);\n const inner = encodeTuple(types, arr);\n return t.size === -1\n ? concatBytes([padLeft(toBeArray(arr.length), WordSize), inner])\n : inner;\n }\n case \"tuple\":\n return encodeTuple(t.components, v as unknown[]);\n }\n}\n\nfunction concatBytes(parts: Uint8Array[]): Uint8Array {\n const total = parts.reduce((s, p) => s + p.length, 0);\n const out = new Uint8Array(total);\n let off = 0;\n for (const p of parts) { out.set(p, off); off += p.length; }\n return out;\n}\n\nfunction encodeTuple(types: AbiType[], values: unknown[]): Uint8Array {\n assertCheck(types.length === values.length, \"tuple: length mismatch\");\n const heads: Uint8Array[] = [];\n const tails: Uint8Array[] = [];\n const headSize = types.reduce((s, t) => s + (isDynamic(t) ? WordSize : staticSize(t)), 0);\n let tailOff = headSize;\n for (let i = 0; i < types.length; i++) {\n const enc = encodeValue(types[i], values[i]);\n if (isDynamic(types[i])) {\n heads.push(padLeft(toBeArray(tailOff), WordSize));\n tails.push(enc);\n tailOff += enc.length;\n } else {\n heads.push(enc);\n }\n }\n return concatBytes([...heads, ...tails]);\n}\n\nfunction ensureRange(data: Uint8Array, offset: number, len: number, what: string): void {\n if (offset < 0 || len < 0 || offset + len > data.length) {\n throw new Error(\n `ABI decode: out-of-bounds read for ${what} ` +\n `(offset=${offset}, length=${len}, data.length=${data.length})`,\n );\n }\n}\n\nfunction decodeValue(t: AbiType, data: Uint8Array, base: number): unknown {\n switch (t.kind) {\n case \"uint\": {\n ensureRange(data, base, WordSize, `${t.signed ? \"int\" : \"uint\"}${t.bits}`);\n const raw = toBigInt(data.slice(base, base + WordSize));\n const masked = mask(raw, t.bits);\n return t.signed ? fromTwos(masked, t.bits) : masked;\n }\n case \"address\":\n ensureRange(data, base, WordSize, \"address\");\n return getAddress(hexlify(data.slice(base + 12, base + WordSize)));\n case \"bool\":\n ensureRange(data, base, WordSize, \"bool\");\n return data[base + 31] !== 0;\n case \"bytesN\":\n ensureRange(data, base, WordSize, `bytes${t.size}`);\n return hexlify(data.slice(base, base + t.size));\n case \"bytes\": {\n ensureRange(data, base, WordSize, \"bytes length\");\n const len = toNumber(data.slice(base, base + WordSize));\n ensureRange(data, base + WordSize, len, \"bytes payload\");\n return hexlify(data.slice(base + WordSize, base + WordSize + len));\n }\n case \"string\": {\n ensureRange(data, base, WordSize, \"string length\");\n const len = toNumber(data.slice(base, base + WordSize));\n ensureRange(data, base + WordSize, len, \"string payload\");\n return fromUtf8Bytes(data.slice(base + WordSize, base + WordSize + len));\n }\n case \"array\": {\n if (t.size === -1) {\n ensureRange(data, base, WordSize, \"array length\");\n const len = toNumber(data.slice(base, base + WordSize));\n // Bound the element count before allocating, so a hostile length\n // word can't trigger an out-of-memory allocation. Each element\n // occupies a fixed head footprint in the array body: a 32-byte\n // offset slot for a dynamic element, its static size for a static\n // one. Zero-footprint elements (e.g. empty tuples) consume no\n // body bytes, so there is nothing to bound the length against;\n // cap those by an absolute length instead.\n const elementHeadSize = isDynamic(t.child)\n ? WordSize\n : staticSize(t.child);\n const bodyBytes = data.length - (base + WordSize);\n const maxElements =\n elementHeadSize > 0\n ? Math.floor(bodyBytes / elementHeadSize)\n : MaxZeroFootprintArrayLen;\n if (len > maxElements) {\n throw new Error(\n `ABI decode: array length ${len} exceeds payload capacity ` +\n `(maxElements=${maxElements}, data.length=${data.length})`,\n );\n }\n return decodeTupleAt(Array<AbiType>(len).fill(t.child), data, base + WordSize);\n }\n return decodeTupleAt(Array<AbiType>(t.size).fill(t.child), data, base);\n }\n case \"tuple\":\n return decodeTupleAt(t.components, data, base);\n }\n}\n\nfunction decodeTupleAt(types: AbiType[], data: Uint8Array, base: number): unknown[] {\n const out: unknown[] = [];\n let head = 0;\n for (const t of types) {\n if (isDynamic(t)) {\n ensureRange(data, base + head, WordSize, \"tuple offset slot\");\n const off = toNumber(data.slice(base + head, base + head + WordSize));\n if (off < 0 || base + off > data.length) {\n throw new Error(\n `ABI decode: tuple dynamic offset out-of-bounds ` +\n `(offset=${off}, base=${base}, data.length=${data.length})`,\n );\n }\n out.push(decodeValue(t, data, base + off));\n head += WordSize;\n } else {\n const size = staticSize(t);\n ensureRange(data, base + head, size, `tuple static slot (${t.kind})`);\n out.push(decodeValue(t, data, base + head));\n head += size;\n }\n }\n return out;\n}\n\nexport function encodeAbiParameters(\n types: ReadonlyArray<string>,\n values: ReadonlyArray<unknown>,\n): Hex {\n assertCheck(types.length === values.length, \"encodeAbiParameters: length mismatch\");\n return hexlify(encodeTuple(types.map(parseType), values as unknown[]));\n}\n\n// Caller-asserted return shape: the generic T is not validated against `types`\n// at compile time or runtime. Mismatched (types, T) pairs will mistype values.\nexport function decodeAbiParameters<T extends readonly unknown[] = unknown[]>(\n types: ReadonlyArray<string>,\n data: BytesLike,\n): T {\n return decodeTupleAt(types.map(parseType), getBytes(data), 0) as unknown as T;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// EIP-712 typed data (src.ts/hash/typed-data.ts — TypedDataEncoder collapsed)\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst hexTrue = toBeHex(BN_1, 32);\nconst hexFalse = toBeHex(BN_0, 32);\n\nfunction hexPadRight(value: BytesLike): Hex {\n const bytes = getBytes(value);\n const padOffset = bytes.length % WordSize;\n if (padOffset) return concat([bytes, Padding.slice(padOffset)]);\n return hexlify(bytes);\n}\n\nfunction getBaseEncoder(type: string): null | ((value: unknown) => Hex) {\n {\n const match = type.match(/^(u?)int(\\d+)$/);\n if (match) {\n const signed = match[1] === \"\";\n const width = parseInt(match[2]);\n assertArgument(\n width % 8 === 0 && width !== 0 && width <= 256 && match[2] === String(width),\n \"invalid numeric width\", \"type\", type,\n );\n const boundsUpper = mask(BN_MAX_UINT256, signed ? width - 1 : width);\n const boundsLower = signed ? (boundsUpper + BN_1) * -1n : BN_0;\n return (v: unknown) => {\n const value = getBigInt(v as BigNumberish, \"value\");\n assertCheck(value >= boundsLower && value <= boundsUpper, `value out-of-bounds for ${type}`);\n return toBeHex(signed ? toTwos(value, 256) : value, 32);\n };\n }\n }\n {\n const match = type.match(/^bytes(\\d+)$/);\n if (match) {\n const width = parseInt(match[1]);\n assertArgument(width !== 0 && width <= 32 && match[1] === String(width), \"invalid bytes width\", \"type\", type);\n return (v: unknown) => {\n const bytes = getBytes(v as BytesLike);\n assertCheck(bytes.length === width, `invalid length for ${type}`);\n return hexPadRight(v as BytesLike);\n };\n }\n }\n switch (type) {\n case \"address\": return (v: unknown) => zeroPadValue(getAddress(v as string), 32);\n case \"bool\": return (v: unknown) => (!v ? hexFalse : hexTrue);\n case \"bytes\": return (v: unknown) => keccak256(v as BytesLike);\n case \"string\": return (v: unknown) => id(v as string);\n }\n return null;\n}\n\ntype ArrayResult = { base: string; index?: string; array?: { base: string; prefix: string; count: number } };\n\nfunction splitArray(type: string): ArrayResult {\n //const match = type.match(/^([^\\[]*)((\\[\\d*\\])*)(\\[(\\d*)\\])$/);\n const match = type.match(/^([^\\x5b]*)((\\x5b\\d*\\x5d)*)(\\x5b(\\d*)\\x5d)$/); \n if (match) {\n return {\n base: match[1],\n index: match[2] + match[4],\n array: { base: match[1], prefix: match[1] + match[2], count: match[5] ? parseInt(match[5]) : -1 },\n };\n }\n return { base: type };\n}\n\nfunction encodeType(name: string, fields: ReadonlyArray<TypedDataField>): string {\n return `${name}(${fields.map(({ name, type }) => type + \" \" + name).join(\",\")})`;\n}\n\n/**\n * Build a recursive encoder for `primaryType` that produces the EIP-712\n * `encodeData` for a struct value. Internal `fullTypes` map captures the\n * fully-described type string for each struct (`MyStruct(...)NestedStruct(...)`).\n */\nfunction buildTypedDataState(_types: Record<string, ReadonlyArray<TypedDataField>>) {\n const fullTypes = new Map<string, string>();\n const links = new Map<string, Set<string>>();\n const parents = new Map<string, string[]>();\n const subtypes = new Map<string, Set<string>>();\n\n const types: Record<string, TypedDataField[]> = {};\n for (const type of Object.keys(_types)) {\n types[type] = _types[type].map(({ name, type }) => {\n let { base, index } = splitArray(type);\n if (base === \"int\" && !_types[\"int\"]) base = \"int256\";\n if (base === \"uint\" && !_types[\"uint\"]) base = \"uint256\";\n return { name, type: base + (index || \"\") };\n });\n links.set(type, new Set());\n parents.set(type, []);\n subtypes.set(type, new Set());\n }\n\n for (const name in types) {\n const uniqueNames = new Set<string>();\n for (const field of types[name]) {\n assertArgument(!uniqueNames.has(field.name), `duplicate variable name ${JSON.stringify(field.name)} in ${JSON.stringify(name)}`, \"types\", _types);\n uniqueNames.add(field.name);\n const baseType = splitArray(field.type).base;\n assertArgument(baseType !== name, `circular type reference to ${JSON.stringify(baseType)}`, \"types\", _types);\n if (getBaseEncoder(baseType)) continue;\n assertArgument(parents.has(baseType), `unknown type ${JSON.stringify(baseType)}`, \"types\", _types);\n parents.get(baseType)!.push(name);\n links.get(name)!.add(baseType);\n }\n }\n\n const primaryTypes = Array.from(parents.keys()).filter((n) => parents.get(n)!.length === 0);\n assertArgument(primaryTypes.length !== 0, \"missing primary type\", \"types\", _types);\n assertArgument(primaryTypes.length === 1, `ambiguous primary types or unused types: ${primaryTypes.map((t) => JSON.stringify(t)).join(\", \")}`, \"types\", _types);\n const primaryType = primaryTypes[0];\n\n function checkCircular(type: string, found: Set<string>): void {\n assertArgument(!found.has(type), `circular type reference to ${JSON.stringify(type)}`, \"types\", _types);\n found.add(type);\n for (const child of links.get(type)!) {\n if (!parents.has(child)) continue;\n checkCircular(child, found);\n for (const subtype of found) subtypes.get(subtype)!.add(child);\n }\n found.delete(type);\n }\n checkCircular(primaryType, new Set());\n\n for (const [name, set] of subtypes) {\n const st = Array.from(set);\n st.sort();\n fullTypes.set(name, encodeType(name, types[name]) + st.map((t) => encodeType(t, types[t])).join(\"\"));\n }\n\n const encoderCache = new Map<string, (value: unknown) => Hex>();\n function getEncoder(type: string): (value: unknown) => Hex {\n const cached = encoderCache.get(type);\n if (cached) return cached;\n const built = buildEncoder(type);\n encoderCache.set(type, built);\n return built;\n }\n function buildEncoder(type: string): (value: unknown) => Hex {\n const base = getBaseEncoder(type);\n if (base) return base;\n const arr = splitArray(type).array;\n if (arr) {\n const subtype = arr.prefix;\n const subEncoder = getEncoder(subtype);\n return (value: unknown) => {\n const arrVal = value as unknown[];\n assertCheck(arr.count === -1 || arr.count === arrVal.length, `array length mismatch; expected ${arr.count}`);\n let result = arrVal.map(subEncoder) as Hex[];\n if (fullTypes.has(subtype)) result = result.map(keccak256);\n return keccak256(concat(result));\n };\n }\n const fields = types[type];\n if (fields) {\n const encodedType = id(fullTypes.get(type)!);\n return (value: unknown) => {\n const obj = value as Record<string, unknown>;\n const values = fields.map(({ name, type }) => {\n const r = getEncoder(type)(obj[name]);\n return fullTypes.has(type) ? keccak256(r) : r;\n });\n values.unshift(encodedType);\n return concat(values);\n };\n }\n assertArgument(false, `unknown type: ${type}`, \"type\", type);\n }\n\n function hashStruct(name: string, value: Record<string, unknown>): Hex {\n return keccak256(getEncoder(name)(value));\n }\n\n return { primaryType, hashStruct };\n}\n\nconst domainFieldTypes: Record<string, string> = {\n name: \"string\",\n version: \"string\",\n chainId: \"uint256\",\n verifyingContract: \"address\",\n salt: \"bytes32\",\n};\nconst domainFieldNames = [\"name\", \"version\", \"chainId\", \"verifyingContract\", \"salt\"];\n\nfunction hashDomain(domain: TypedDataDomain): Hex {\n const domainFields: TypedDataField[] = [];\n for (const name in domain) {\n const v = (domain as Record<string, unknown>)[name];\n if (v == null) continue;\n const type = domainFieldTypes[name];\n assertArgument(!!type, `invalid typed-data domain key: ${JSON.stringify(name)}`, \"domain\", domain);\n domainFields.push({ name, type });\n }\n domainFields.sort((a, b) => domainFieldNames.indexOf(a.name) - domainFieldNames.indexOf(b.name));\n const { hashStruct } = buildTypedDataState({ EIP712Domain: domainFields });\n return hashStruct(\"EIP712Domain\", domain as Record<string, unknown>);\n}\n\nexport function hashTypedData(\n domain: TypedDataDomain,\n types: Record<string, ReadonlyArray<TypedDataField>>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: Record<string, any>,\n): Hex {\n // Strip EIP712Domain from user types (ethers does this implicitly).\n const userTypes: Record<string, ReadonlyArray<TypedDataField>> = {};\n for (const [k, v] of Object.entries(types)) if (k !== \"EIP712Domain\") userTypes[k] = v;\n const { primaryType, hashStruct } = buildTypedDataState(userTypes);\n return keccak256(concat([\"0x1901\", hashDomain(domain), hashStruct(primaryType, value)]));\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Signing (src.ts/crypto/{signing-key,signature}.ts + transaction/address.ts)\n// Class-free: privateKeyToAddress + signHash + signTypedData functions only.\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction computePublicKey(privateKey: BytesLike): Hex {\n const bytes = getBytes(privateKey, \"key\");\n assertCheck(bytes.length === 32, \"invalid private key\");\n return hexlify(secp256k1.getPublicKey(bytes, false));\n}\n\n// Mirrors `Wallet` constructor (src.ts/wallet/wallet.ts:42-44): accept\n// unprefixed hex at the public signing API while keeping internal `getBytes`\n// strict.\nfunction normalizePrivateKey(key: string): string {\n return key.startsWith(\"0x\") ? key : \"0x\" + key;\n}\n\nexport function privateKeyToAddress(privateKey: string): Hex {\n const pub = computePublicKey(normalizePrivateKey(privateKey));\n return getAddress(keccak256((\"0x\" + pub.substring(4)) as Hex).substring(26));\n}\n\nexport function signHash(privateKey: string, hash: BytesLike): Signature {\n assertCheck(dataLength(hash) === 32, \"invalid digest length\");\n const sig = secp256k1.sign(getBytesCopy(hash), getBytesCopy(normalizePrivateKey(privateKey)), { lowS: true });\n const r = toBeHex(sig.r, 32);\n const s = toBeHex(sig.s, 32);\n const yParity = (sig.recovery & 1) as 0 | 1;\n const v = (27 + yParity) as 27 | 28;\n return {\n r,\n s,\n v,\n yParity,\n serialized: concat([r, s, new Uint8Array([v])]),\n };\n}\n\nexport function signTypedData(\n privateKey: string,\n domain: TypedDataDomain,\n types: Record<string, ReadonlyArray<TypedDataField>>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n message: Record<string, any>,\n): Hex {\n return signHash(privateKey, hashTypedData(domain, types, message)).serialized;\n}\n","//cr