(encodedData: string)
| 26 | } |
| 27 | |
| 28 | export function decode(encodedData: string): DecodedMap { |
| 29 | // Special cases for empty parameters |
| 30 | if (encodedData === '0x') { |
| 31 | return {}; |
| 32 | } |
| 33 | |
| 34 | // Alternatively: |
| 35 | // const header = encodedData.substring(0, 66); |
| 36 | const header = ethers.utils.hexlify(ethers.utils.arrayify(encodedData).slice(0, 32)); |
| 37 | const parsedHeader = ethers.utils.parseBytes32String(header); |
| 38 | |
| 39 | // Get and validate the first character of the header |
| 40 | const encodedEncodingVersion = parsedHeader.substring(0, 1); |
| 41 | if (encodedEncodingVersion !== '1') { |
| 42 | throw new Error(`Unknown ABI schema version: ${encodedEncodingVersion}`); |
| 43 | } |
| 44 | |
| 45 | // The version is specified by the first byte and the parameters are specified by the rest |
| 46 | const encodedParameterTypes = parsedHeader.substring(1); |
| 47 | |
| 48 | // Replace encoded types with full type names |
| 49 | const fullParameterTypes: ParameterType[] = Array.from(encodedParameterTypes).map( |
| 50 | (type) => PARAMETER_SHORT_TYPES[type as ParameterTypeShort] |
| 51 | ); |
| 52 | |
| 53 | // The first `bytes32` is the type encoding |
| 54 | const initialDecodedTypes: ParameterType[] = ['bytes32']; |
| 55 | |
| 56 | const decodingTypes = fullParameterTypes.reduce((acc: string[], type) => { |
| 57 | // Each parameter is expected to have a `bytes32` name |
| 58 | return [...acc, 'bytes32' as const, TYPE_TRANSFORMATIONS[type] ?? type]; |
| 59 | }, initialDecodedTypes); |
| 60 | |
| 61 | // It's important to leave the `encodedData` intact here and not try to trim off the first |
| 62 | // 32 bytes (i.e. the header) because that results in the decoding failing. So decode |
| 63 | // exactly what you got from the contract, including the header. |
| 64 | const decodedData = ethers.utils.defaultAbiCoder.decode(decodingTypes, encodedData); |
| 65 | |
| 66 | // Checks if the original encoded data matches the re-encoded data |
| 67 | const reEncodedData = ethers.utils.defaultAbiCoder.encode(decodingTypes, decodedData); |
| 68 | if (reEncodedData !== encodedData) { |
| 69 | throw new Error('Re-encoding mismatch'); |
| 70 | } |
| 71 | |
| 72 | const [_version, ...decodedParameters] = decodedData; |
| 73 | const nameValuePairs = chunk(decodedParameters, 2) as [string, string][]; |
| 74 | |
| 75 | return buildDecodedMap(fullParameterTypes, nameValuePairs); |
| 76 | } |
no test coverage detected