
cc.youchain.abi.FunctionReturnDecoder Maven / Gradle / Ivy
package cc.youchain.abi;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import cc.youchain.abi.datatypes.Array;
import cc.youchain.abi.datatypes.Bytes;
import cc.youchain.abi.datatypes.BytesType;
import cc.youchain.abi.datatypes.DynamicArray;
import cc.youchain.abi.datatypes.DynamicBytes;
import cc.youchain.abi.datatypes.StaticArray;
import cc.youchain.abi.datatypes.Type;
import cc.youchain.abi.datatypes.Utf8String;
import cc.youchain.abi.datatypes.generated.Bytes32;
import cc.youchain.utils.Numeric;
import cc.youchain.utils.Strings;
import static cc.youchain.abi.TypeDecoder.MAX_BYTE_LENGTH_FOR_HEX_STRING;
/**
* Decodes values returned by function or event calls.
*/
public class FunctionReturnDecoder {
private FunctionReturnDecoder() { }
/**
* Decode ABI encoded return values from smart contract function call.
*
* @param rawInput ABI encoded input
* @param outputParameters list of return types as {@link TypeReference}
* @return {@link List} of values returned by function, {@link Collections#emptyList()} if
* invalid response
*/
public static List decode(
String rawInput, List> outputParameters) {
String input = Numeric.cleanHexPrefix(rawInput);
if (Strings.isEmpty(input)) {
return Collections.emptyList();
} else {
return build(input, outputParameters);
}
}
/**
* Decodes an indexed parameter associated with an event. Indexed parameters are individually
* encoded, unlike non-indexed parameters which are encoded as per ABI-encoded function
* parameters and return values.
*
* If any of the following types are indexed, the Keccak-256 hashes of the values are
* returned instead. These are returned as a bytes32 value.
*
*
* - Arrays
* - Strings
* - Bytes
*
*
* See the
*
* Solidity documentation for further information.
*
* @param rawInput ABI encoded input
* @param typeReference of expected result type
* @param type of TypeReference
* @return the decode value
*/
@SuppressWarnings("unchecked")
public static Type decodeIndexedValue(
String rawInput, TypeReference typeReference) {
String input = Numeric.cleanHexPrefix(rawInput);
try {
Class type = typeReference.getClassType();
if (Bytes.class.isAssignableFrom(type)) {
return TypeDecoder.decodeBytes(input, (Class) Class.forName(type.getName()));
} else if (Array.class.isAssignableFrom(type)
|| BytesType.class.isAssignableFrom(type)
|| Utf8String.class.isAssignableFrom(type)) {
return TypeDecoder.decodeBytes(input, Bytes32.class);
} else {
return TypeDecoder.decode(input, type);
}
} catch (ClassNotFoundException e) {
throw new UnsupportedOperationException("Invalid class reference provided", e);
}
}
private static List build(
String input, List> outputParameters) {
List results = new ArrayList<>(outputParameters.size());
int offset = 0;
for (TypeReference> typeReference:outputParameters) {
try {
@SuppressWarnings("unchecked")
Class type = (Class) typeReference.getClassType();
int hexStringDataOffset = getDataOffset(input, offset, type);
Type result;
if (DynamicArray.class.isAssignableFrom(type)) {
result = TypeDecoder.decodeDynamicArray(
input, hexStringDataOffset, typeReference);
offset += MAX_BYTE_LENGTH_FOR_HEX_STRING;
} else if (typeReference instanceof TypeReference.StaticArrayTypeReference) {
int length = ((TypeReference.StaticArrayTypeReference) typeReference).getSize();
result = TypeDecoder.decodeStaticArray(
input, hexStringDataOffset, typeReference, length);
offset += length * MAX_BYTE_LENGTH_FOR_HEX_STRING;
} else if (StaticArray.class.isAssignableFrom(type)) {
int length = Integer.parseInt(type.getSimpleName()
.substring(StaticArray.class.getSimpleName().length()));
result = TypeDecoder.decodeStaticArray(
input, hexStringDataOffset, typeReference, length);
offset += length * MAX_BYTE_LENGTH_FOR_HEX_STRING;
} else {
result = TypeDecoder.decode(input, hexStringDataOffset, type);
offset += MAX_BYTE_LENGTH_FOR_HEX_STRING;
}
results.add(result);
} catch (ClassNotFoundException e) {
throw new UnsupportedOperationException("Invalid class reference provided", e);
}
}
return results;
}
private static int getDataOffset(String input, int offset, Class type) {
if (DynamicBytes.class.isAssignableFrom(type)
|| Utf8String.class.isAssignableFrom(type)
|| DynamicArray.class.isAssignableFrom(type)) {
return TypeDecoder.decodeUintAsInt(input, offset) << 1;
} else {
return offset;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy