org.nervos.appchain.abi.FunctionEncoder Maven / Gradle / Ivy
package org.nervos.appchain.abi;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import org.nervos.appchain.abi.datatypes.Function;
import org.nervos.appchain.abi.datatypes.StaticArray;
import org.nervos.appchain.abi.datatypes.Type;
import org.nervos.appchain.abi.datatypes.Uint;
import org.nervos.appchain.crypto.Hash;
import org.nervos.appchain.utils.Numeric;
/**
* Ethereum Contract Application Binary Interface (ABI) encoding for functions.
* Further details are available
* here.
*
*/
public class FunctionEncoder {
private FunctionEncoder() { }
public static String encode(Function function) {
List parameters = function.getInputParameters();
String methodSignature = buildMethodSignature(function.getName(), parameters);
String methodId = buildMethodId(methodSignature);
StringBuilder result = new StringBuilder();
result.append(methodId);
return encodeParameters(parameters, result);
}
public static String encodeConstructor(List parameters) {
return encodeParameters(parameters, new StringBuilder());
}
private static String encodeParameters(List parameters, StringBuilder result) {
int dynamicDataOffset = getLength(parameters) * Type.MAX_BYTE_LENGTH;
StringBuilder dynamicData = new StringBuilder();
for (Type parameter:parameters) {
String encodedValue = TypeEncoder.encode(parameter);
if (TypeEncoder.isDynamic(parameter)) {
String encodedDataOffset = TypeEncoder.encodeNumeric(
new Uint(BigInteger.valueOf(dynamicDataOffset)));
result.append(encodedDataOffset);
dynamicData.append(encodedValue);
dynamicDataOffset += encodedValue.length() >> 1;
} else {
result.append(encodedValue);
}
}
result.append(dynamicData);
return result.toString();
}
private static int getLength(List parameters) {
int count = 0;
for (Type type:parameters) {
if (type instanceof StaticArray) {
count += ((StaticArray) type).getValue().size();
} else {
count++;
}
}
return count;
}
static String buildMethodSignature(String methodName, List parameters) {
StringBuilder result = new StringBuilder();
result.append(methodName);
result.append("(");
List types = new ArrayList(parameters.size());
String params = "";
for (int i = 0; i < parameters.size(); i++) {
Type type = parameters.get(i);
params += type.getTypeAsString();
if (i + 1 < parameters.size()) {
params += ","; // no whitespace
}
types.add(type.getTypeAsString());
}
result.append(params);
result.append(")");
return result.toString();
}
static String buildMethodId(String methodSignature) {
byte[] input = methodSignature.getBytes();
byte[] hash = Hash.sha3(input);
return Numeric.toHexString(hash).substring(0, 10);
}
}