UNPKG

viem

Version:

TypeScript Interface for Ethereum

212 lines • 8.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.decodeAbiParameters = void 0; const abi_js_1 = require("../../errors/abi.js"); const getAddress_js_1 = require("../address/getAddress.js"); const size_js_1 = require("../data/size.js"); const slice_js_1 = require("../data/slice.js"); const trim_js_1 = require("../data/trim.js"); const fromHex_js_1 = require("../encoding/fromHex.js"); const encodeAbiParameters_js_1 = require("./encodeAbiParameters.js"); function decodeAbiParameters(params, data) { if (data === '0x' && params.length > 0) throw new abi_js_1.AbiDecodingZeroDataError(); if ((0, size_js_1.size)(data) && (0, size_js_1.size)(data) < 32) throw new abi_js_1.AbiDecodingDataSizeTooSmallError({ data, params: params, size: (0, size_js_1.size)(data), }); return decodeParams({ data, params: params, }); } exports.decodeAbiParameters = decodeAbiParameters; function decodeParams({ data, params, }) { const decodedValues = []; let position = 0; for (let i = 0; i < params.length; i++) { if (position >= (0, size_js_1.size)(data)) throw new abi_js_1.AbiDecodingDataSizeTooSmallError({ data, params, size: (0, size_js_1.size)(data), }); const param = params[i]; const { consumed, value } = decodeParam({ data, param, position }); decodedValues.push(value); position += consumed; } return decodedValues; } function decodeParam({ data, param, position, }) { const arrayComponents = (0, encodeAbiParameters_js_1.getArrayComponents)(param.type); if (arrayComponents) { const [length, type] = arrayComponents; return decodeArray(data, { length, param: { ...param, type: type }, position, }); } if (param.type === 'tuple') { return decodeTuple(data, { param: param, position }); } if (param.type === 'string') { return decodeString(data, { position }); } if (param.type.startsWith('bytes')) { return decodeBytes(data, { param, position }); } const value = (0, slice_js_1.slice)(data, position, position + 32, { strict: true }); if (param.type.startsWith('uint') || param.type.startsWith('int')) { return decodeNumber(value, { param }); } if (param.type === 'address') { return decodeAddress(value); } if (param.type === 'bool') { return decodeBool(value); } throw new abi_js_1.InvalidAbiDecodingTypeError(param.type, { docsPath: '/docs/contract/decodeAbiParameters', }); } function decodeAddress(value) { return { consumed: 32, value: (0, getAddress_js_1.checksumAddress)((0, slice_js_1.slice)(value, -20)) }; } function decodeArray(data, { param, length, position, }) { if (!length) { const offset = (0, fromHex_js_1.hexToNumber)((0, slice_js_1.slice)(data, position, position + 32, { strict: true })); if (offset < position) throw new abi_js_1.AbiDecodingOffsetOutOfBoundsError({ offset, position }); const length = (0, fromHex_js_1.hexToNumber)((0, slice_js_1.slice)(data, offset, offset + 32, { strict: true })); let consumed = 0; const value = []; for (let i = 0; i < length; ++i) { const decodedChild = decodeParam({ data: (0, slice_js_1.slice)(data, offset + 32), param, position: consumed, }); consumed += decodedChild.consumed; value.push(decodedChild.value); } return { value, consumed: 32 }; } if (hasDynamicChild(param)) { const arrayComponents = (0, encodeAbiParameters_js_1.getArrayComponents)(param.type); const dynamicChild = !arrayComponents?.[0]; let consumed = 0; const value = []; for (let i = 0; i < length; ++i) { const offset = (0, fromHex_js_1.hexToNumber)((0, slice_js_1.slice)(data, position, position + 32, { strict: true })); const decodedChild = decodeParam({ data: (0, slice_js_1.slice)(data, offset), param, position: dynamicChild ? consumed : i * 32, }); consumed += decodedChild.consumed; value.push(decodedChild.value); } return { value, consumed: 32 }; } let consumed = 0; const value = []; for (let i = 0; i < length; ++i) { const decodedChild = decodeParam({ data, param, position: position + consumed, }); consumed += decodedChild.consumed; value.push(decodedChild.value); } return { value, consumed }; } function decodeBool(value) { return { consumed: 32, value: (0, fromHex_js_1.hexToBool)(value) }; } function decodeBytes(data, { param, position }) { const [_, size] = param.type.split('bytes'); if (!size) { const offset = (0, fromHex_js_1.hexToNumber)((0, slice_js_1.slice)(data, position, position + 32, { strict: true })); const length = (0, fromHex_js_1.hexToNumber)((0, slice_js_1.slice)(data, offset, offset + 32, { strict: true })); if (length === 0) return { consumed: 32, value: '0x' }; const value = (0, slice_js_1.slice)(data, offset + 32, offset + 32 + length, { strict: true, }); return { consumed: 32, value }; } const value = (0, slice_js_1.slice)(data, position, position + parseInt(size), { strict: true, }); return { consumed: 32, value }; } function decodeNumber(value, { param }) { const signed = param.type.startsWith('int'); const size = parseInt(param.type.split('int')[1] || '256'); return { consumed: 32, value: size > 48 ? (0, fromHex_js_1.hexToBigInt)(value, { signed }) : (0, fromHex_js_1.hexToNumber)(value, { signed }), }; } function decodeString(data, { position }) { const offset = (0, fromHex_js_1.hexToNumber)((0, slice_js_1.slice)(data, position, position + 32, { strict: true })); const length = (0, fromHex_js_1.hexToNumber)((0, slice_js_1.slice)(data, offset, offset + 32, { strict: true })); if (length === 0) return { consumed: 32, value: '' }; const value = (0, fromHex_js_1.hexToString)((0, trim_js_1.trim)((0, slice_js_1.slice)(data, offset + 32, offset + 32 + length, { strict: true }))); return { consumed: 32, value }; } function decodeTuple(data, { param, position }) { const hasUnnamedChild = param.components.length === 0 || param.components.some(({ name }) => !name); const value = hasUnnamedChild ? [] : {}; let consumed = 0; if (hasDynamicChild(param)) { const offset = (0, fromHex_js_1.hexToNumber)((0, slice_js_1.slice)(data, position, position + 32, { strict: true })); for (let i = 0; i < param.components.length; ++i) { const component = param.components[i]; const decodedChild = decodeParam({ data: (0, slice_js_1.slice)(data, offset), param: component, position: consumed, }); consumed += decodedChild.consumed; value[hasUnnamedChild ? i : component?.name] = decodedChild.value; } return { consumed: 32, value }; } for (let i = 0; i < param.components.length; ++i) { const component = param.components[i]; const decodedChild = decodeParam({ data, param: component, position: position + consumed, }); consumed += decodedChild.consumed; value[hasUnnamedChild ? i : component?.name] = decodedChild.value; } return { consumed, value }; } function hasDynamicChild(param) { const { type } = param; if (type === 'string') return true; if (type === 'bytes') return true; if (type.endsWith('[]')) return true; if (type === 'tuple') return param.components?.some(hasDynamicChild); const arrayComponents = (0, encodeAbiParameters_js_1.getArrayComponents)(param.type); if (arrayComponents && hasDynamicChild({ ...param, type: arrayComponents[1] })) return true; return false; } //# sourceMappingURL=decodeAbiParameters.js.map