org.web3j.abi.TypeEncoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of abi Show documentation
Show all versions of abi Show documentation
Ethereum Application Binary Interface (ABI) for working with smart contracts
package org.web3j.abi;
import java.math.BigInteger;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Array;
import org.web3j.abi.datatypes.Bool;
import org.web3j.abi.datatypes.Bytes;
import org.web3j.abi.datatypes.BytesType;
import org.web3j.abi.datatypes.DynamicArray;
import org.web3j.abi.datatypes.DynamicBytes;
import org.web3j.abi.datatypes.NumericType;
import org.web3j.abi.datatypes.StaticArray;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.Ufixed;
import org.web3j.abi.datatypes.Uint;
import org.web3j.abi.datatypes.Utf8String;
import org.web3j.compat.Compat;
import org.web3j.utils.Numeric;
import static org.web3j.abi.datatypes.Type.MAX_BIT_LENGTH;
import static org.web3j.abi.datatypes.Type.MAX_BYTE_LENGTH;
/**
* Ethereum Contract Application Binary Interface (ABI) encoding for types.
* Further details are available
* here.
*
*/
public class TypeEncoder {
private TypeEncoder() { }
static boolean isDynamic(Type parameter) {
return parameter instanceof DynamicBytes
|| parameter instanceof Utf8String
|| parameter instanceof DynamicArray;
}
@SuppressWarnings("unchecked")
public static String encode(Type parameter) {
if (parameter instanceof NumericType) {
return encodeNumeric(((NumericType) parameter));
} else if (parameter instanceof Address) {
return encodeAddress((Address) parameter);
} else if (parameter instanceof Bool) {
return encodeBool((Bool) parameter);
} else if (parameter instanceof Bytes) {
return encodeBytes((Bytes) parameter);
} else if (parameter instanceof DynamicBytes) {
return encodeDynamicBytes((DynamicBytes) parameter);
} else if (parameter instanceof Utf8String) {
return encodeString((Utf8String) parameter);
} else if (parameter instanceof StaticArray) {
return encodeArrayValues((StaticArray) parameter);
} else if (parameter instanceof DynamicArray) {
return encodeDynamicArray((DynamicArray) parameter);
} else {
throw new UnsupportedOperationException(
"Type cannot be encoded: " + parameter.getClass());
}
}
static String encodeAddress(Address address) {
return encodeNumeric(address.toUint160());
}
static String encodeNumeric(NumericType numericType) {
byte[] rawValue = toByteArray(numericType);
byte paddingValue = getPaddingValue(numericType);
byte[] paddedRawValue = new byte[MAX_BYTE_LENGTH];
if (paddingValue != 0) {
for (int i = 0; i < paddedRawValue.length; i++) {
paddedRawValue[i] = paddingValue;
}
}
System.arraycopy(
rawValue, 0,
paddedRawValue, MAX_BYTE_LENGTH - rawValue.length,
rawValue.length);
return Numeric.toHexStringNoPrefix(paddedRawValue);
}
private static byte getPaddingValue(NumericType numericType) {
if (numericType.getValue().signum() == -1) {
return (byte) 0xff;
} else {
return 0;
}
}
private static byte[] toByteArray(NumericType numericType) {
BigInteger value = numericType.getValue();
if (numericType instanceof Ufixed || numericType instanceof Uint) {
if (value.bitLength() == MAX_BIT_LENGTH) {
// As BigInteger is signed, if we have a 256 bit value, the resultant byte array
// will contain a sign byte in it's MSB, which we should ignore for this unsigned
// integer type.
byte[] byteArray = new byte[MAX_BYTE_LENGTH];
System.arraycopy(value.toByteArray(), 1, byteArray, 0, MAX_BYTE_LENGTH);
return byteArray;
}
}
return value.toByteArray();
}
static String encodeBool(Bool value) {
byte[] rawValue = new byte[MAX_BYTE_LENGTH];
if (value.getValue()) {
rawValue[rawValue.length - 1] = 1;
}
return Numeric.toHexStringNoPrefix(rawValue);
}
static String encodeBytes(BytesType bytesType) {
byte[] value = bytesType.getValue();
int length = value.length;
int mod = length % MAX_BYTE_LENGTH;
byte[] dest;
if (mod != 0) {
int padding = MAX_BYTE_LENGTH - mod;
dest = new byte[length + padding];
System.arraycopy(value, 0, dest, 0, length);
} else {
dest = value;
}
return Numeric.toHexStringNoPrefix(dest);
}
static String encodeDynamicBytes(DynamicBytes dynamicBytes) {
int size = dynamicBytes.getValue().length;
String encodedLength = encode(new Uint(BigInteger.valueOf(size)));
String encodedValue = encodeBytes(dynamicBytes);
StringBuilder result = new StringBuilder();
result.append(encodedLength);
result.append(encodedValue);
return result.toString();
}
static String encodeString(Utf8String string) {
byte[] utfEncoded = string.getValue().getBytes(Compat.UTF_8);
return encodeDynamicBytes(new DynamicBytes(utfEncoded));
}
static String encodeArrayValues(Array value) {
StringBuilder result = new StringBuilder();
for (Type type:value.getValue()) {
result.append(TypeEncoder.encode(type));
}
return result.toString();
}
static String encodeDynamicArray(DynamicArray value) {
int size = value.getValue().size();
String encodedLength = encode(new Uint(BigInteger.valueOf(size)));
String encodedValues = encodeArrayValues(value);
StringBuilder result = new StringBuilder();
result.append(encodedLength);
result.append(encodedValues);
return result.toString();
}
}