UNPKG

@flaunch/sdk

Version:

Flaunch SDK to easily interact with the Flaunch protocol

1,473 lines (1,442 loc) 173 kB
import { hexToBigInt as hexToBigInt$1, pad as pad$1, encodeAbiParameters } from 'viem'; import axios from 'axios'; const bytes32ToUint256 = (value) => { return hexToBigInt$1(value); }; const uint256ToBytes32 = (value) => { return pad$1(encodeAbiParameters([{ type: "uint256", name: "value" }], [value]), { size: 32, dir: "right" }); }; // List of public IPFS gateways to cycle through const IPFS_GATEWAYS = [ "https://gateway.pinata.cloud/ipfs/", "https://ipfs.io/ipfs/", "https://dweb.link/ipfs/", ]; // Counter to track the current gateway index let currentGatewayIndex = 0; const resolveIPFS = (value) => { if (value.startsWith("ipfs://")) { const cid = value.slice(7); // Get the next gateway and increment the counter const gateway = IPFS_GATEWAYS[currentGatewayIndex]; // Update the counter, cycling back to 0 when we reach the end currentGatewayIndex = (currentGatewayIndex + 1) % IPFS_GATEWAYS.length; return `${gateway}${cid}`; } return value; }; /** * Uploads a file to IPFS using Pinata * @param params Configuration and file data * @returns Upload response with CID and other details */ const uploadFileToIPFS = async (params) => { try { const formData = new FormData(); formData.append("file", params.file); const pinataMetadata = { name: params.name || null, keyvalues: params.metadata || {}, }; formData.append("pinataMetadata", JSON.stringify(pinataMetadata)); const pinataOptions = { cidVersion: 1, }; formData.append("pinataOptions", JSON.stringify(pinataOptions)); const response = await axios.post("https://api.pinata.cloud/pinning/pinFileToIPFS", formData, { headers: { Authorization: `Bearer ${params.pinataConfig.jwt}`, "Content-Type": "multipart/form-data", }, }); return { IpfsHash: response.data.IpfsHash, PinSize: response.data.PinSize, Timestamp: response.data.Timestamp, isDuplicate: response.data.isDuplicate || false, }; } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Failed to upload file to IPFS: ${error.response?.data?.message || error.message}`); } throw error; } }; /** * Uploads JSON data to IPFS using Pinata * @param params Configuration and JSON data * @returns Upload response with CID and other details */ const uploadJsonToIPFS = async (params) => { try { const requestBody = { pinataOptions: { cidVersion: 1, }, pinataMetadata: { name: params.name || null, keyvalues: params.metadata || {}, }, pinataContent: params.json, }; const response = await axios.post("https://api.pinata.cloud/pinning/pinJSONToIPFS", requestBody, { headers: { Authorization: `Bearer ${params.pinataConfig.jwt}`, "Content-Type": "application/json", }, }); return { IpfsHash: response.data.IpfsHash, PinSize: response.data.PinSize, Timestamp: response.data.Timestamp, isDuplicate: response.data.isDuplicate || false, }; } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Failed to upload JSON to IPFS: ${error.response?.data?.message || error.message}`); } throw error; } }; /** * Uploads a base64 image to IPFS using Pinata * @param params Configuration and base64 image data * @returns Upload response with CID and other details */ const uploadImageToIPFS = async (params) => { try { const formData = new FormData(); // Convert base64 to Blob and then to File // Remove data URL prefix if present (e.g., "data:image/jpeg;base64,") const base64Data = params.base64Image.split(",")[1] || params.base64Image; const byteCharacters = atob(base64Data); const byteArrays = []; for (let offset = 0; offset < byteCharacters.length; offset += 1024) { const slice = byteCharacters.slice(offset, offset + 1024); const byteNumbers = new Array(slice.length); for (let i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } // Detect mime type from base64 string let mimeType = "image/png"; // default if (params.base64Image.startsWith("data:")) { mimeType = params.base64Image.split(";")[0].split(":")[1]; } const blob = new Blob(byteArrays, { type: mimeType }); const fileName = params.name || `image.${mimeType.split("/")[1]}`; const file = new File([blob], fileName, { type: mimeType }); formData.append("file", file); const pinataMetadata = { name: params.name || null, keyvalues: params.metadata || {}, }; formData.append("pinataMetadata", JSON.stringify(pinataMetadata)); const pinataOptions = { cidVersion: 1, }; formData.append("pinataOptions", JSON.stringify(pinataOptions)); const response = await axios.post("https://api.pinata.cloud/pinning/pinFileToIPFS", formData, { headers: { Authorization: `Bearer ${params.pinataConfig.jwt}`, "Content-Type": "multipart/form-data", }, }); return { IpfsHash: response.data.IpfsHash, PinSize: response.data.PinSize, Timestamp: response.data.Timestamp, isDuplicate: response.data.isDuplicate || false, }; } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Failed to upload image to IPFS: ${error.response?.data?.message || error.message}`); } throw error; } }; const generateTokenUri = async (name, params) => { // 1. upload image to IPFS const imageRes = await uploadImageToIPFS({ pinataConfig: params.pinataConfig, base64Image: params.metadata.base64Image, }); // 2. upload metadata to IPFS const coinMetadata = { name, description: params.metadata.description, image: `ipfs://${imageRes.IpfsHash}`, external_link: params.metadata.websiteUrl || "", collaborators: [], discordUrl: params.metadata.discordUrl || "", twitterUrl: params.metadata.twitterUrl || "", telegramUrl: params.metadata.telegramUrl || "", }; const metadataRes = await uploadJsonToIPFS({ pinataConfig: params.pinataConfig, json: coinMetadata, }); return `ipfs://${metadataRes.IpfsHash}`; }; function defineChain(chain) { return { formatters: undefined, fees: undefined, serializers: undefined, ...chain, }; } const version = '2.29.2'; let errorConfig = { getDocsUrl: ({ docsBaseUrl, docsPath = '', docsSlug, }) => docsPath ? `${docsBaseUrl ?? 'https://viem.sh'}${docsPath}${docsSlug ? `#${docsSlug}` : ''}` : undefined, version: `viem@${version}`, }; class BaseError extends Error { constructor(shortMessage, args = {}) { const details = (() => { if (args.cause instanceof BaseError) return args.cause.details; if (args.cause?.message) return args.cause.message; return args.details; })(); const docsPath = (() => { if (args.cause instanceof BaseError) return args.cause.docsPath || args.docsPath; return args.docsPath; })(); const docsUrl = errorConfig.getDocsUrl?.({ ...args, docsPath }); const message = [ shortMessage || 'An error occurred.', '', ...(args.metaMessages ? [...args.metaMessages, ''] : []), ...(docsUrl ? [`Docs: ${docsUrl}`] : []), ...(details ? [`Details: ${details}`] : []), ...(errorConfig.version ? [`Version: ${errorConfig.version}`] : []), ].join('\n'); super(message, args.cause ? { cause: args.cause } : undefined); Object.defineProperty(this, "details", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "docsPath", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "metaMessages", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "shortMessage", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "version", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'BaseError' }); this.details = details; this.docsPath = docsPath; this.metaMessages = args.metaMessages; this.name = args.name ?? this.name; this.shortMessage = shortMessage; this.version = version; } walk(fn) { return walk(this, fn); } } function walk(err, fn) { if (fn?.(err)) return err; if (err && typeof err === 'object' && 'cause' in err && err.cause !== undefined) return walk(err.cause, fn); return fn ? null : err; } class IntegerOutOfRangeError extends BaseError { constructor({ max, min, signed, size, value, }) { super(`Number "${value}" is not in safe ${size ? `${size * 8}-bit ${signed ? 'signed' : 'unsigned'} ` : ''}integer range ${max ? `(${min} to ${max})` : `(above ${min})`}`, { name: 'IntegerOutOfRangeError' }); } } class SizeOverflowError extends BaseError { constructor({ givenSize, maxSize }) { super(`Size cannot exceed ${maxSize} bytes. Given size: ${givenSize} bytes.`, { name: 'SizeOverflowError' }); } } function isHex(value, { strict = true } = {}) { if (!value) return false; if (typeof value !== 'string') return false; return strict ? /^0x[0-9a-fA-F]*$/.test(value) : value.startsWith('0x'); } /** * @description Retrieves the size of the value (in bytes). * * @param value The value (hex or byte array) to retrieve the size of. * @returns The size of the value (in bytes). */ function size(value) { if (isHex(value, { strict: false })) return Math.ceil((value.length - 2) / 2); return value.length; } function trim(hexOrBytes, { dir = 'left' } = {}) { let data = typeof hexOrBytes === 'string' ? hexOrBytes.replace('0x', '') : hexOrBytes; let sliceLength = 0; for (let i = 0; i < data.length - 1; i++) { if (data[dir === 'left' ? i : data.length - i - 1].toString() === '0') sliceLength++; else break; } data = dir === 'left' ? data.slice(sliceLength) : data.slice(0, data.length - sliceLength); if (typeof hexOrBytes === 'string') { if (data.length === 1 && dir === 'right') data = `${data}0`; return `0x${data.length % 2 === 1 ? `0${data}` : data}`; } return data; } class SliceOffsetOutOfBoundsError extends BaseError { constructor({ offset, position, size, }) { super(`Slice ${position === 'start' ? 'starting' : 'ending'} at offset "${offset}" is out-of-bounds (size: ${size}).`, { name: 'SliceOffsetOutOfBoundsError' }); } } class SizeExceedsPaddingSizeError extends BaseError { constructor({ size, targetSize, type, }) { super(`${type.charAt(0).toUpperCase()}${type .slice(1) .toLowerCase()} size (${size}) exceeds padding size (${targetSize}).`, { name: 'SizeExceedsPaddingSizeError' }); } } function pad(hexOrBytes, { dir, size = 32 } = {}) { if (typeof hexOrBytes === 'string') return padHex(hexOrBytes, { dir, size }); return padBytes(hexOrBytes, { dir, size }); } function padHex(hex_, { dir, size = 32 } = {}) { if (size === null) return hex_; const hex = hex_.replace('0x', ''); if (hex.length > size * 2) throw new SizeExceedsPaddingSizeError({ size: Math.ceil(hex.length / 2), targetSize: size, type: 'hex', }); return `0x${hex[dir === 'right' ? 'padEnd' : 'padStart'](size * 2, '0')}`; } function padBytes(bytes, { dir, size = 32 } = {}) { if (size === null) return bytes; if (bytes.length > size) throw new SizeExceedsPaddingSizeError({ size: bytes.length, targetSize: size, type: 'bytes', }); const paddedBytes = new Uint8Array(size); for (let i = 0; i < size; i++) { const padEnd = dir === 'right'; paddedBytes[padEnd ? i : size - i - 1] = bytes[padEnd ? i : bytes.length - i - 1]; } return paddedBytes; } const hexes = /*#__PURE__*/ Array.from({ length: 256 }, (_v, i) => i.toString(16).padStart(2, '0')); /** * Encodes a string, number, bigint, or ByteArray into a hex string * * - Docs: https://viem.sh/docs/utilities/toHex * - Example: https://viem.sh/docs/utilities/toHex#usage * * @param value Value to encode. * @param opts Options. * @returns Hex value. * * @example * import { toHex } from 'viem' * const data = toHex('Hello world') * // '0x48656c6c6f20776f726c6421' * * @example * import { toHex } from 'viem' * const data = toHex(420) * // '0x1a4' * * @example * import { toHex } from 'viem' * const data = toHex('Hello world', { size: 32 }) * // '0x48656c6c6f20776f726c64210000000000000000000000000000000000000000' */ function toHex(value, opts = {}) { if (typeof value === 'number' || typeof value === 'bigint') return numberToHex(value, opts); if (typeof value === 'string') { return stringToHex(value, opts); } if (typeof value === 'boolean') return boolToHex(value, opts); return bytesToHex(value, opts); } /** * Encodes a boolean into a hex string * * - Docs: https://viem.sh/docs/utilities/toHex#booltohex * * @param value Value to encode. * @param opts Options. * @returns Hex value. * * @example * import { boolToHex } from 'viem' * const data = boolToHex(true) * // '0x1' * * @example * import { boolToHex } from 'viem' * const data = boolToHex(false) * // '0x0' * * @example * import { boolToHex } from 'viem' * const data = boolToHex(true, { size: 32 }) * // '0x0000000000000000000000000000000000000000000000000000000000000001' */ function boolToHex(value, opts = {}) { const hex = `0x${Number(value)}`; if (typeof opts.size === 'number') { assertSize(hex, { size: opts.size }); return pad(hex, { size: opts.size }); } return hex; } /** * Encodes a bytes array into a hex string * * - Docs: https://viem.sh/docs/utilities/toHex#bytestohex * * @param value Value to encode. * @param opts Options. * @returns Hex value. * * @example * import { bytesToHex } from 'viem' * const data = bytesToHex(Uint8Array.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]) * // '0x48656c6c6f20576f726c6421' * * @example * import { bytesToHex } from 'viem' * const data = bytesToHex(Uint8Array.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]), { size: 32 }) * // '0x48656c6c6f20576f726c64210000000000000000000000000000000000000000' */ function bytesToHex(value, opts = {}) { let string = ''; for (let i = 0; i < value.length; i++) { string += hexes[value[i]]; } const hex = `0x${string}`; if (typeof opts.size === 'number') { assertSize(hex, { size: opts.size }); return pad(hex, { dir: 'right', size: opts.size }); } return hex; } /** * Encodes a number or bigint into a hex string * * - Docs: https://viem.sh/docs/utilities/toHex#numbertohex * * @param value Value to encode. * @param opts Options. * @returns Hex value. * * @example * import { numberToHex } from 'viem' * const data = numberToHex(420) * // '0x1a4' * * @example * import { numberToHex } from 'viem' * const data = numberToHex(420, { size: 32 }) * // '0x00000000000000000000000000000000000000000000000000000000000001a4' */ function numberToHex(value_, opts = {}) { const { signed, size } = opts; const value = BigInt(value_); let maxValue; if (size) { if (signed) maxValue = (1n << (BigInt(size) * 8n - 1n)) - 1n; else maxValue = 2n ** (BigInt(size) * 8n) - 1n; } else if (typeof value_ === 'number') { maxValue = BigInt(Number.MAX_SAFE_INTEGER); } const minValue = typeof maxValue === 'bigint' && signed ? -maxValue - 1n : 0; if ((maxValue && value > maxValue) || value < minValue) { const suffix = typeof value_ === 'bigint' ? 'n' : ''; throw new IntegerOutOfRangeError({ max: maxValue ? `${maxValue}${suffix}` : undefined, min: `${minValue}${suffix}`, signed, size, value: `${value_}${suffix}`, }); } const hex = `0x${(signed && value < 0 ? (1n << BigInt(size * 8)) + BigInt(value) : value).toString(16)}`; if (size) return pad(hex, { size }); return hex; } const encoder$1 = /*#__PURE__*/ new TextEncoder(); /** * Encodes a UTF-8 string into a hex string * * - Docs: https://viem.sh/docs/utilities/toHex#stringtohex * * @param value Value to encode. * @param opts Options. * @returns Hex value. * * @example * import { stringToHex } from 'viem' * const data = stringToHex('Hello World!') * // '0x48656c6c6f20576f726c6421' * * @example * import { stringToHex } from 'viem' * const data = stringToHex('Hello World!', { size: 32 }) * // '0x48656c6c6f20576f726c64210000000000000000000000000000000000000000' */ function stringToHex(value_, opts = {}) { const value = encoder$1.encode(value_); return bytesToHex(value, opts); } const encoder = /*#__PURE__*/ new TextEncoder(); /** * Encodes a UTF-8 string, hex value, bigint, number or boolean to a byte array. * * - Docs: https://viem.sh/docs/utilities/toBytes * - Example: https://viem.sh/docs/utilities/toBytes#usage * * @param value Value to encode. * @param opts Options. * @returns Byte array value. * * @example * import { toBytes } from 'viem' * const data = toBytes('Hello world') * // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]) * * @example * import { toBytes } from 'viem' * const data = toBytes(420) * // Uint8Array([1, 164]) * * @example * import { toBytes } from 'viem' * const data = toBytes(420, { size: 4 }) * // Uint8Array([0, 0, 1, 164]) */ function toBytes$1(value, opts = {}) { if (typeof value === 'number' || typeof value === 'bigint') return numberToBytes(value, opts); if (typeof value === 'boolean') return boolToBytes(value, opts); if (isHex(value)) return hexToBytes(value, opts); return stringToBytes(value, opts); } /** * Encodes a boolean into a byte array. * * - Docs: https://viem.sh/docs/utilities/toBytes#booltobytes * * @param value Boolean value to encode. * @param opts Options. * @returns Byte array value. * * @example * import { boolToBytes } from 'viem' * const data = boolToBytes(true) * // Uint8Array([1]) * * @example * import { boolToBytes } from 'viem' * const data = boolToBytes(true, { size: 32 }) * // Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]) */ function boolToBytes(value, opts = {}) { const bytes = new Uint8Array(1); bytes[0] = Number(value); if (typeof opts.size === 'number') { assertSize(bytes, { size: opts.size }); return pad(bytes, { size: opts.size }); } return bytes; } // We use very optimized technique to convert hex string to byte array const charCodeMap = { zero: 48, nine: 57, A: 65, F: 70, a: 97, f: 102, }; function charCodeToBase16(char) { if (char >= charCodeMap.zero && char <= charCodeMap.nine) return char - charCodeMap.zero; if (char >= charCodeMap.A && char <= charCodeMap.F) return char - (charCodeMap.A - 10); if (char >= charCodeMap.a && char <= charCodeMap.f) return char - (charCodeMap.a - 10); return undefined; } /** * Encodes a hex string into a byte array. * * - Docs: https://viem.sh/docs/utilities/toBytes#hextobytes * * @param hex Hex string to encode. * @param opts Options. * @returns Byte array value. * * @example * import { hexToBytes } from 'viem' * const data = hexToBytes('0x48656c6c6f20776f726c6421') * // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]) * * @example * import { hexToBytes } from 'viem' * const data = hexToBytes('0x48656c6c6f20776f726c6421', { size: 32 }) * // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) */ function hexToBytes(hex_, opts = {}) { let hex = hex_; if (opts.size) { assertSize(hex, { size: opts.size }); hex = pad(hex, { dir: 'right', size: opts.size }); } let hexString = hex.slice(2); if (hexString.length % 2) hexString = `0${hexString}`; const length = hexString.length / 2; const bytes = new Uint8Array(length); for (let index = 0, j = 0; index < length; index++) { const nibbleLeft = charCodeToBase16(hexString.charCodeAt(j++)); const nibbleRight = charCodeToBase16(hexString.charCodeAt(j++)); if (nibbleLeft === undefined || nibbleRight === undefined) { throw new BaseError(`Invalid byte sequence ("${hexString[j - 2]}${hexString[j - 1]}" in "${hexString}").`); } bytes[index] = nibbleLeft * 16 + nibbleRight; } return bytes; } /** * Encodes a number into a byte array. * * - Docs: https://viem.sh/docs/utilities/toBytes#numbertobytes * * @param value Number to encode. * @param opts Options. * @returns Byte array value. * * @example * import { numberToBytes } from 'viem' * const data = numberToBytes(420) * // Uint8Array([1, 164]) * * @example * import { numberToBytes } from 'viem' * const data = numberToBytes(420, { size: 4 }) * // Uint8Array([0, 0, 1, 164]) */ function numberToBytes(value, opts) { const hex = numberToHex(value, opts); return hexToBytes(hex); } /** * Encodes a UTF-8 string into a byte array. * * - Docs: https://viem.sh/docs/utilities/toBytes#stringtobytes * * @param value String to encode. * @param opts Options. * @returns Byte array value. * * @example * import { stringToBytes } from 'viem' * const data = stringToBytes('Hello world!') * // Uint8Array([72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33]) * * @example * import { stringToBytes } from 'viem' * const data = stringToBytes('Hello world!', { size: 32 }) * // Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) */ function stringToBytes(value, opts = {}) { const bytes = encoder.encode(value); if (typeof opts.size === 'number') { assertSize(bytes, { size: opts.size }); return pad(bytes, { dir: 'right', size: opts.size }); } return bytes; } function assertSize(hexOrBytes, { size: size$1 }) { if (size(hexOrBytes) > size$1) throw new SizeOverflowError({ givenSize: size(hexOrBytes), maxSize: size$1, }); } /** * Decodes a hex value into a bigint. * * - Docs: https://viem.sh/docs/utilities/fromHex#hextobigint * * @param hex Hex value to decode. * @param opts Options. * @returns BigInt value. * * @example * import { hexToBigInt } from 'viem' * const data = hexToBigInt('0x1a4', { signed: true }) * // 420n * * @example * import { hexToBigInt } from 'viem' * const data = hexToBigInt('0x00000000000000000000000000000000000000000000000000000000000001a4', { size: 32 }) * // 420n */ function hexToBigInt(hex, opts = {}) { const { signed } = opts; if (opts.size) assertSize(hex, { size: opts.size }); const value = BigInt(hex); if (!signed) return value; const size = (hex.length - 2) / 2; const max = (1n << (BigInt(size) * 8n - 1n)) - 1n; if (value <= max) return value; return value - BigInt(`0x${'f'.padStart(size * 2, 'f')}`) - 1n; } /** * Decodes a hex string into a number. * * - Docs: https://viem.sh/docs/utilities/fromHex#hextonumber * * @param hex Hex value to decode. * @param opts Options. * @returns Number value. * * @example * import { hexToNumber } from 'viem' * const data = hexToNumber('0x1a4') * // 420 * * @example * import { hexToNumber } from 'viem' * const data = hexToBigInt('0x00000000000000000000000000000000000000000000000000000000000001a4', { size: 32 }) * // 420 */ function hexToNumber(hex, opts = {}) { return Number(hexToBigInt(hex, opts)); } function defineFormatter(type, format) { return ({ exclude, format: overrides, }) => { return { exclude, format: (args) => { const formatted = format(args); if (exclude) { for (const key of exclude) { delete formatted[key]; } } return { ...formatted, ...overrides(args), }; }, type, }; }; } const transactionType = { '0x0': 'legacy', '0x1': 'eip2930', '0x2': 'eip1559', '0x3': 'eip4844', '0x4': 'eip7702', }; function formatTransaction(transaction) { const transaction_ = { ...transaction, blockHash: transaction.blockHash ? transaction.blockHash : null, blockNumber: transaction.blockNumber ? BigInt(transaction.blockNumber) : null, chainId: transaction.chainId ? hexToNumber(transaction.chainId) : undefined, gas: transaction.gas ? BigInt(transaction.gas) : undefined, gasPrice: transaction.gasPrice ? BigInt(transaction.gasPrice) : undefined, maxFeePerBlobGas: transaction.maxFeePerBlobGas ? BigInt(transaction.maxFeePerBlobGas) : undefined, maxFeePerGas: transaction.maxFeePerGas ? BigInt(transaction.maxFeePerGas) : undefined, maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? BigInt(transaction.maxPriorityFeePerGas) : undefined, nonce: transaction.nonce ? hexToNumber(transaction.nonce) : undefined, to: transaction.to ? transaction.to : null, transactionIndex: transaction.transactionIndex ? Number(transaction.transactionIndex) : null, type: transaction.type ? transactionType[transaction.type] : undefined, typeHex: transaction.type ? transaction.type : undefined, value: transaction.value ? BigInt(transaction.value) : undefined, v: transaction.v ? BigInt(transaction.v) : undefined, }; if (transaction.authorizationList) transaction_.authorizationList = formatAuthorizationList$1(transaction.authorizationList); transaction_.yParity = (() => { // If `yParity` is provided, we will use it. if (transaction.yParity) return Number(transaction.yParity); // If no `yParity` provided, try derive from `v`. if (typeof transaction_.v === 'bigint') { if (transaction_.v === 0n || transaction_.v === 27n) return 0; if (transaction_.v === 1n || transaction_.v === 28n) return 1; if (transaction_.v >= 35n) return transaction_.v % 2n === 0n ? 1 : 0; } return undefined; })(); if (transaction_.type === 'legacy') { delete transaction_.accessList; delete transaction_.maxFeePerBlobGas; delete transaction_.maxFeePerGas; delete transaction_.maxPriorityFeePerGas; delete transaction_.yParity; } if (transaction_.type === 'eip2930') { delete transaction_.maxFeePerBlobGas; delete transaction_.maxFeePerGas; delete transaction_.maxPriorityFeePerGas; } if (transaction_.type === 'eip1559') { delete transaction_.maxFeePerBlobGas; } return transaction_; } const defineTransaction = /*#__PURE__*/ defineFormatter('transaction', formatTransaction); ////////////////////////////////////////////////////////////////////////////// function formatAuthorizationList$1(authorizationList) { return authorizationList.map((authorization) => ({ address: authorization.address, chainId: Number(authorization.chainId), nonce: Number(authorization.nonce), r: authorization.r, s: authorization.s, yParity: Number(authorization.yParity), })); } function formatBlock(block) { const transactions = (block.transactions ?? []).map((transaction) => { if (typeof transaction === 'string') return transaction; return formatTransaction(transaction); }); return { ...block, baseFeePerGas: block.baseFeePerGas ? BigInt(block.baseFeePerGas) : null, blobGasUsed: block.blobGasUsed ? BigInt(block.blobGasUsed) : undefined, difficulty: block.difficulty ? BigInt(block.difficulty) : undefined, excessBlobGas: block.excessBlobGas ? BigInt(block.excessBlobGas) : undefined, gasLimit: block.gasLimit ? BigInt(block.gasLimit) : undefined, gasUsed: block.gasUsed ? BigInt(block.gasUsed) : undefined, hash: block.hash ? block.hash : null, logsBloom: block.logsBloom ? block.logsBloom : null, nonce: block.nonce ? block.nonce : null, number: block.number ? BigInt(block.number) : null, size: block.size ? BigInt(block.size) : undefined, timestamp: block.timestamp ? BigInt(block.timestamp) : undefined, transactions, totalDifficulty: block.totalDifficulty ? BigInt(block.totalDifficulty) : null, }; } const defineBlock = /*#__PURE__*/ defineFormatter('block', formatBlock); function formatLog(log, { args, eventName, } = {}) { return { ...log, blockHash: log.blockHash ? log.blockHash : null, blockNumber: log.blockNumber ? BigInt(log.blockNumber) : null, logIndex: log.logIndex ? Number(log.logIndex) : null, transactionHash: log.transactionHash ? log.transactionHash : null, transactionIndex: log.transactionIndex ? Number(log.transactionIndex) : null, ...(eventName ? { args, eventName } : {}), }; } const receiptStatuses = { '0x0': 'reverted', '0x1': 'success', }; function formatTransactionReceipt(transactionReceipt) { const receipt = { ...transactionReceipt, blockNumber: transactionReceipt.blockNumber ? BigInt(transactionReceipt.blockNumber) : null, contractAddress: transactionReceipt.contractAddress ? transactionReceipt.contractAddress : null, cumulativeGasUsed: transactionReceipt.cumulativeGasUsed ? BigInt(transactionReceipt.cumulativeGasUsed) : null, effectiveGasPrice: transactionReceipt.effectiveGasPrice ? BigInt(transactionReceipt.effectiveGasPrice) : null, gasUsed: transactionReceipt.gasUsed ? BigInt(transactionReceipt.gasUsed) : null, logs: transactionReceipt.logs ? transactionReceipt.logs.map((log) => formatLog(log)) : null, to: transactionReceipt.to ? transactionReceipt.to : null, transactionIndex: transactionReceipt.transactionIndex ? hexToNumber(transactionReceipt.transactionIndex) : null, status: transactionReceipt.status ? receiptStatuses[transactionReceipt.status] : null, type: transactionReceipt.type ? transactionType[transactionReceipt.type] || transactionReceipt.type : null, }; if (transactionReceipt.blobGasPrice) receipt.blobGasPrice = BigInt(transactionReceipt.blobGasPrice); if (transactionReceipt.blobGasUsed) receipt.blobGasUsed = BigInt(transactionReceipt.blobGasUsed); return receipt; } const defineTransactionReceipt = /*#__PURE__*/ defineFormatter('transactionReceipt', formatTransactionReceipt); const rpcTransactionType = { legacy: '0x0', eip2930: '0x1', eip1559: '0x2', eip4844: '0x3', eip7702: '0x4', }; function formatTransactionRequest(request) { const rpcRequest = {}; if (typeof request.authorizationList !== 'undefined') rpcRequest.authorizationList = formatAuthorizationList(request.authorizationList); if (typeof request.accessList !== 'undefined') rpcRequest.accessList = request.accessList; if (typeof request.blobVersionedHashes !== 'undefined') rpcRequest.blobVersionedHashes = request.blobVersionedHashes; if (typeof request.blobs !== 'undefined') { if (typeof request.blobs[0] !== 'string') rpcRequest.blobs = request.blobs.map((x) => bytesToHex(x)); else rpcRequest.blobs = request.blobs; } if (typeof request.data !== 'undefined') rpcRequest.data = request.data; if (typeof request.from !== 'undefined') rpcRequest.from = request.from; if (typeof request.gas !== 'undefined') rpcRequest.gas = numberToHex(request.gas); if (typeof request.gasPrice !== 'undefined') rpcRequest.gasPrice = numberToHex(request.gasPrice); if (typeof request.maxFeePerBlobGas !== 'undefined') rpcRequest.maxFeePerBlobGas = numberToHex(request.maxFeePerBlobGas); if (typeof request.maxFeePerGas !== 'undefined') rpcRequest.maxFeePerGas = numberToHex(request.maxFeePerGas); if (typeof request.maxPriorityFeePerGas !== 'undefined') rpcRequest.maxPriorityFeePerGas = numberToHex(request.maxPriorityFeePerGas); if (typeof request.nonce !== 'undefined') rpcRequest.nonce = numberToHex(request.nonce); if (typeof request.to !== 'undefined') rpcRequest.to = request.to; if (typeof request.type !== 'undefined') rpcRequest.type = rpcTransactionType[request.type]; if (typeof request.value !== 'undefined') rpcRequest.value = numberToHex(request.value); return rpcRequest; } const defineTransactionRequest = /*#__PURE__*/ defineFormatter('transactionRequest', formatTransactionRequest); ////////////////////////////////////////////////////////////////////////////// function formatAuthorizationList(authorizationList) { return authorizationList.map((authorization) => ({ address: authorization.address, r: authorization.r ? numberToHex(BigInt(authorization.r)) : authorization.r, s: authorization.s ? numberToHex(BigInt(authorization.s)) : authorization.s, chainId: numberToHex(authorization.chainId), nonce: numberToHex(authorization.nonce), ...(typeof authorization.yParity !== 'undefined' ? { yParity: numberToHex(authorization.yParity) } : {}), ...(typeof authorization.v !== 'undefined' && typeof authorization.yParity === 'undefined' ? { v: numberToHex(authorization.v) } : {}), })); } const maxUint256 = 2n ** 256n - 1n; function concatHex(values) { return `0x${values.reduce((acc, x) => acc + x.replace('0x', ''), '')}`; } class NegativeOffsetError extends BaseError { constructor({ offset }) { super(`Offset \`${offset}\` cannot be negative.`, { name: 'NegativeOffsetError', }); } } class PositionOutOfBoundsError extends BaseError { constructor({ length, position }) { super(`Position \`${position}\` is out of bounds (\`0 < position < ${length}\`).`, { name: 'PositionOutOfBoundsError' }); } } class RecursiveReadLimitExceededError extends BaseError { constructor({ count, limit }) { super(`Recursive read limit of \`${limit}\` exceeded (recursive read count: \`${count}\`).`, { name: 'RecursiveReadLimitExceededError' }); } } const staticCursor = { bytes: new Uint8Array(), dataView: new DataView(new ArrayBuffer(0)), position: 0, positionReadCount: new Map(), recursiveReadCount: 0, recursiveReadLimit: Number.POSITIVE_INFINITY, assertReadLimit() { if (this.recursiveReadCount >= this.recursiveReadLimit) throw new RecursiveReadLimitExceededError({ count: this.recursiveReadCount + 1, limit: this.recursiveReadLimit, }); }, assertPosition(position) { if (position < 0 || position > this.bytes.length - 1) throw new PositionOutOfBoundsError({ length: this.bytes.length, position, }); }, decrementPosition(offset) { if (offset < 0) throw new NegativeOffsetError({ offset }); const position = this.position - offset; this.assertPosition(position); this.position = position; }, getReadCount(position) { return this.positionReadCount.get(position || this.position) || 0; }, incrementPosition(offset) { if (offset < 0) throw new NegativeOffsetError({ offset }); const position = this.position + offset; this.assertPosition(position); this.position = position; }, inspectByte(position_) { const position = position_ ?? this.position; this.assertPosition(position); return this.bytes[position]; }, inspectBytes(length, position_) { const position = position_ ?? this.position; this.assertPosition(position + length - 1); return this.bytes.subarray(position, position + length); }, inspectUint8(position_) { const position = position_ ?? this.position; this.assertPosition(position); return this.bytes[position]; }, inspectUint16(position_) { const position = position_ ?? this.position; this.assertPosition(position + 1); return this.dataView.getUint16(position); }, inspectUint24(position_) { const position = position_ ?? this.position; this.assertPosition(position + 2); return ((this.dataView.getUint16(position) << 8) + this.dataView.getUint8(position + 2)); }, inspectUint32(position_) { const position = position_ ?? this.position; this.assertPosition(position + 3); return this.dataView.getUint32(position); }, pushByte(byte) { this.assertPosition(this.position); this.bytes[this.position] = byte; this.position++; }, pushBytes(bytes) { this.assertPosition(this.position + bytes.length - 1); this.bytes.set(bytes, this.position); this.position += bytes.length; }, pushUint8(value) { this.assertPosition(this.position); this.bytes[this.position] = value; this.position++; }, pushUint16(value) { this.assertPosition(this.position + 1); this.dataView.setUint16(this.position, value); this.position += 2; }, pushUint24(value) { this.assertPosition(this.position + 2); this.dataView.setUint16(this.position, value >> 8); this.dataView.setUint8(this.position + 2, value & ~4294967040); this.position += 3; }, pushUint32(value) { this.assertPosition(this.position + 3); this.dataView.setUint32(this.position, value); this.position += 4; }, readByte() { this.assertReadLimit(); this._touch(); const value = this.inspectByte(); this.position++; return value; }, readBytes(length, size) { this.assertReadLimit(); this._touch(); const value = this.inspectBytes(length); this.position += size ?? length; return value; }, readUint8() { this.assertReadLimit(); this._touch(); const value = this.inspectUint8(); this.position += 1; return value; }, readUint16() { this.assertReadLimit(); this._touch(); const value = this.inspectUint16(); this.position += 2; return value; }, readUint24() { this.assertReadLimit(); this._touch(); const value = this.inspectUint24(); this.position += 3; return value; }, readUint32() { this.assertReadLimit(); this._touch(); const value = this.inspectUint32(); this.position += 4; return value; }, get remaining() { return this.bytes.length - this.position; }, setPosition(position) { const oldPosition = this.position; this.assertPosition(position); this.position = position; return () => (this.position = oldPosition); }, _touch() { if (this.recursiveReadLimit === Number.POSITIVE_INFINITY) return; const count = this.getReadCount(); this.positionReadCount.set(this.position, count + 1); if (count > 0) this.recursiveReadCount++; }, }; function createCursor(bytes, { recursiveReadLimit = 8_192 } = {}) { const cursor = Object.create(staticCursor); cursor.bytes = bytes; cursor.dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); cursor.positionReadCount = new Map(); cursor.recursiveReadLimit = recursiveReadLimit; return cursor; } function toRlp(bytes, to = 'hex') { const encodable = getEncodable(bytes); const cursor = createCursor(new Uint8Array(encodable.length)); encodable.encode(cursor); if (to === 'hex') return bytesToHex(cursor.bytes); return cursor.bytes; } function getEncodable(bytes) { if (Array.isArray(bytes)) return getEncodableList(bytes.map((x) => getEncodable(x))); return getEncodableBytes(bytes); } function getEncodableList(list) { const bodyLength = list.reduce((acc, x) => acc + x.length, 0); const sizeOfBodyLength = getSizeOfLength(bodyLength); const length = (() => { if (bodyLength <= 55) return 1 + bodyLength; return 1 + sizeOfBodyLength + bodyLength; })(); return { length, encode(cursor) { if (bodyLength <= 55) { cursor.pushByte(0xc0 + bodyLength); } else { cursor.pushByte(0xc0 + 55 + sizeOfBodyLength); if (sizeOfBodyLength === 1) cursor.pushUint8(bodyLength); else if (sizeOfBodyLength === 2) cursor.pushUint16(bodyLength); else if (sizeOfBodyLength === 3) cursor.pushUint24(bodyLength); else cursor.pushUint32(bodyLength); } for (const { encode } of list) { encode(cursor); } }, }; } function getEncodableBytes(bytesOrHex) { const bytes = typeof bytesOrHex === 'string' ? hexToBytes(bytesOrHex) : bytesOrHex; const sizeOfBytesLength = getSizeOfLength(bytes.length); const length = (() => { if (bytes.length === 1 && bytes[0] < 0x80) return 1; if (bytes.length <= 55) return 1 + bytes.length; return 1 + sizeOfBytesLength + bytes.length; })(); return { length, encode(cursor) { if (bytes.length === 1 && bytes[0] < 0x80) { cursor.pushBytes(bytes); } else if (bytes.length <= 55) { cursor.pushByte(0x80 + bytes.length); cursor.pushBytes(bytes); } else { cursor.pushByte(0x80 + 55 + sizeOfBytesLength); if (sizeOfBytesLength === 1) cursor.pushUint8(bytes.length); else if (sizeOfBytesLength === 2) cursor.pushUint16(bytes.length); else if (sizeOfBytesLength === 3) cursor.pushUint24(bytes.length); else cursor.pushUint32(bytes.length); cursor.pushBytes(bytes); } }, }; } function getSizeOfLength(length) { if (length < 2 ** 8) return 1; if (length < 2 ** 16) return 2; if (length < 2 ** 24) return 3; if (length < 2 ** 32) return 4; throw new BaseError('Length is too large.'); } const gweiUnits = { ether: -9, wei: 9, }; /** * Divides a number by a given exponent of base 10 (10exponent), and formats it into a string representation of the number.. * * - Docs: https://viem.sh/docs/utilities/formatUnits * * @example * import { formatUnits } from 'viem' * * formatUnits(420000000000n, 9) * // '420' */ function formatUnits(value, decimals) { let display = value.toString(); const negative = display.startsWith('-'); if (negative) display = display.slice(1); display = display.padStart(decimals, '0'); let [integer, fraction] = [ display.slice(0, display.length - decimals), display.slice(display.length - decimals), ]; fraction = fraction.replace(/(0+)$/, ''); return `${negative ? '-' : ''}${integer || '0'}${fraction ? `.${fraction}` : ''}`; } /** * Converts numerical wei to a string representation of gwei. * * - Docs: https://viem.sh/docs/utilities/formatGwei * * @example * import { formatGwei } from 'viem' * * formatGwei(1000000000n) * // '1' */ function formatGwei(wei, unit = 'wei') { return formatUnits(wei, gweiUnits[unit]); } function prettyPrint(args) { const entries = Object.entries(args) .map(([key, value]) => { if (value === undefined || value === false) return null; return [key, value]; }) .filter(Boolean); const maxLength = entries.reduce((acc, [key]) => Math.max(acc, key.length), 0); return entries .map(([key, value]) => ` ${`${key}:`.padEnd(maxLength + 1)} ${value}`) .join('\n'); } class InvalidLegacyVError extends BaseError { constructor({ v }) { super(`Invalid \`v\` value "${v}". Expected 27 or 28.`, { name: 'InvalidLegacyVError', }); } } class InvalidSerializableTransactionError extends BaseError { constructor({ transaction }) { super('Cannot infer a transaction type from provided transaction.', { metaMessages: [ 'Provided Transaction:', '{', prettyPrint(transaction), '}', '', 'To infer the type, either provide:', '- a `type` to the Transaction, or', '- an EIP-1559 Transaction with `maxFeePerGas`, or', '- an EIP-2930 Transaction with `gasPrice` & `accessList`, or', '- an EIP-4844 Transaction with `blobs`, `blobVersionedHashes`, `sidecars`, or', '- an EIP-7702 Transaction with `authorizationList`, or', '- a Legacy Transaction with `gasPrice`', ], name: 'InvalidSerializableTransactionError', }); } } class InvalidStorageKeySizeError extends BaseError { constructor({ storageKey }) { super(`Size for storage key "${storageKey}" is invalid. Expected 32 bytes. Got ${Math.floor((storageKey.length - 2) / 2)} bytes.`, { name: 'InvalidStorageKeySizeError' }); } } /* * Serializes an EIP-7702 authorization list. */ function serializeAuthorizationList(authorizationList) { if (!authorizationList || authorizationList.length === 0) return []; const serializedAuthorizationList = []; for (const authorization of authorizationList) { const { chainId, nonce, ...signature } = authorization; const contractAddress = authorization.address; serializedAuthorizationList.push([ chainId ? toHex(chainId) : '0x', contractAddress, nonce ? toHex(nonce) : '0x', ...toYParitySignatureArray({}, signature), ]); } return serializedAuthorizationList; } /** * Compute commitments from a list of blobs. * * @example * ```ts * import { blobsToCommitments, toBlobs } from 'viem' * import { kzg } from './kzg' * * const blobs = toBlobs({ data: '0x1234' }) * const commitments = blobsToCommitments({ blobs, kzg }) * ``` */ function blobsToCommitments(parameters) { const { kzg } = parameters; const to = parameters.to ?? (typeof parameters.blobs[0] === 'string' ? 'hex' : 'bytes'); const blobs = (typeof parameters.blobs[0] === 'string' ? parameters.blobs.map((x) => hexToBytes(x)) : parameters.blobs); const commitments = []; for (const blob of blobs) commitments.push(Uint8Array.from(kzg.blobToKzgCommitment(blob))); re