All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.neow3j.contract.ContractParameter Maven / Gradle / Ivy

package io.neow3j.contract;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import io.neow3j.constants.NeoConstants;
import io.neow3j.contract.ContractParameter.ContractParameterSerializer;
import io.neow3j.crypto.Base64;
import io.neow3j.model.types.ContractParameterType;
import io.neow3j.wallet.Account;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static io.neow3j.model.types.ContractParameterType.ARRAY;
import static io.neow3j.model.types.ContractParameterType.HASH256;
import static io.neow3j.model.types.ContractParameterType.INTEGER;
import static io.neow3j.model.types.ContractParameterType.MAP;
import static io.neow3j.utils.Numeric.hexStringToByteArray;
import static io.neow3j.utils.Numeric.isValidHexString;
import static io.neow3j.utils.Numeric.toHexStringNoPrefix;
import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * Contract parameters represent an input parameter for contract invocations.
 */
@JsonSerialize(using = ContractParameterSerializer.class)
@SuppressWarnings("unchecked")
public class ContractParameter {

    @JsonProperty("name")
    private String paramName;

    @JsonProperty("type")
    private ContractParameterType paramType;

    @JsonProperty("value")
    protected Object value;

    private ContractParameter() {
    }

    public ContractParameter(String name, ContractParameterType paramType, Object value) {
        this.paramName = name;
        this.paramType = paramType;
        this.value = value;
    }

    ContractParameter(String name, ContractParameterType paramType) {
        this(name, paramType, null);
    }

    private ContractParameter(ContractParameterType paramType, Object value) {
        this(null, paramType, value);
    }

    /**
     * Creates a contract parameter from the given value.
     *
     * @param value any object value.
     * @return the contract parameter.
     */
    public static ContractParameter any(Object value) {
        return new ContractParameter(ContractParameterType.ANY, value);
    }

    /**
     * Creates a string parameter from the given value.
     *
     * @param value the string value.
     * @return the contract parameter.
     */
    public static ContractParameter string(String value) {
        return new ContractParameter(ContractParameterType.STRING, value);
    }

    /**
     * Creates an array parameter from the given values.
     * 

* This method supports parameters of types Boolean, Integer, byte[] and String. Array * entries of different contract parameter types first need to be instantiated as a * {@code ContractParameter} and can then be passed as a parameter as well. * * @param entries the array entries. * @return the contract parameter. */ public static ContractParameter array(Object... entries) { if (entries.length == 0) { throw new IllegalArgumentException("At least one parameter is required to create an " + "array contract parameter."); } if (Arrays.stream(entries).anyMatch(Objects::isNull)) { throw new IllegalArgumentException("Cannot add a null object to an array contract " + "parameter."); } ContractParameter[] params = Arrays.stream(entries) .map(ContractParameter::castToContractParameter) .toArray(ContractParameter[]::new); return new ContractParameter(ContractParameterType.ARRAY, params); } /** * Creates an array parameter from the given entries. * * @param entries the array entries in a list. * @return the contract parameter. */ public static ContractParameter array(List entries) { return array(entries.toArray()); } /** * Creates a map contract parameter. *

* The {@code Map} argument can hold any types that can be cast to one of the available * {@link ContractParameterType}s. The types {@link ContractParameterType#ARRAY} and * {@link ContractParameterType#MAP} are not supported as map keys. *

* The first example below uses regular Java types that can automatically be wrapped into a * {@code ContractParameter}. *

     * Map map = new HashMap{@literal <>}();
     * map.put("one", "first");
     * map.put("two", 2);
     * ContractParameter param = map(map);
     * 
* The second example leads to the same result but uses {@code ContractParameter} before * adding elements. *
     * Map map = new HashMap{@literal <>}();
     * map.put(ContractParameter.string("one"), ContractParameter.string("first"));
     * map.put(ContractParameter.integer("two"), ContractParameter.integer(2));
     * ContractParameter param = map(map);
     * 
* * @param map The map entries. * @return the contract parameter. */ public static ContractParameter map(Map map) { if (map.isEmpty()) { throw new IllegalArgumentException("At least one map entry is required to create a " + "map contract parameter."); } Map paramMap = new HashMap<>(); map.forEach((k, v) -> { ContractParameter key = castToContractParameter(k); ContractParameter value = castToContractParameter(v); if (key.getParamType().equals(ARRAY) || key.getParamType().equals(MAP)) { throw new IllegalArgumentException("The provided map contains an invalid key. The" + " keys cannot be of type array or map."); } paramMap.put(key, value); }); return new ContractParameter(ContractParameterType.MAP, paramMap); } private static ContractParameter castToContractParameter(Object o) { if (o instanceof ContractParameter) { return (ContractParameter) o; } else if (o instanceof Boolean) { return bool((Boolean) o); } else if (o instanceof Integer) { return integer((Integer) o); } else if (o instanceof byte[]) { return byteArray((byte[]) o); } else if (o instanceof String) { return string((String) o); } else { throw new IllegalArgumentException("The provided object could not be casted into " + "a supported contract parameter type."); } } /** * Creates a byte array parameter from the given value. *

* Make sure that the array is in the right byte order, i.e., endianness. * * @param byteArray the parameter value. * @return the contract parameter. */ public static ContractParameter byteArray(byte[] byteArray) { return new ContractParameter(ContractParameterType.BYTE_ARRAY, byteArray); } /** * Creates a byte array parameter from the given hex string. * * @param hexString the hexadecimal string. * @return the contract parameter. */ public static ContractParameter byteArray(String hexString) { if (!isValidHexString(hexString)) { throw new IllegalArgumentException("Argument is not a valid hex number."); } return byteArray(hexStringToByteArray(hexString)); } /** * Create a byte array parameter from a string by converting the string to bytes using the UTF-8 * character set. * * @param value the parameter value. * @return the contract parameter. */ public static ContractParameter byteArrayFromString(String value) { return byteArray(value.getBytes(UTF_8)); } /** * Creates a signature parameter from the given signature hexadecimal string. * * @param signatureHexString a signature as hexadecimal string. * @return the contract parameter. */ public static ContractParameter signature(String signatureHexString) { if (!isValidHexString(signatureHexString)) { throw new IllegalArgumentException("Argument is not a valid hex number."); } return signature(hexStringToByteArray(signatureHexString)); } /** * Creates a signature parameter from the given signature. * * @param signature a signature. * @return the contract parameter. */ public static ContractParameter signature(byte[] signature) { if (signature.length != NeoConstants.SIGNATURE_SIZE) { throw new IllegalArgumentException("Signature is expected to have a length of " + NeoConstants.SIGNATURE_SIZE + " bytes, but had " + signature.length + "."); } return new ContractParameter(ContractParameterType.SIGNATURE, signature); } /** * Creates a boolean parameter from the given boolean. * * @param bool a boolean value. * @return the contract parameter. */ public static ContractParameter bool(boolean bool) { return new ContractParameter(ContractParameterType.BOOLEAN, bool); } /** * Creates an integer parameter from the given integer. * * @param integer an integer value. * @return the contract parameter. */ public static ContractParameter integer(int integer) { return integer(BigInteger.valueOf(integer)); } /** * Creates an integer parameter from the given integer. * * @param integer an integer value. * @return the contract parameter. */ public static ContractParameter integer(BigInteger integer) { return new ContractParameter(INTEGER, integer); } /** * Creates a hash160 parameter from the given account. * * @param account an account. * @return the contract parameter. */ public static ContractParameter hash160(Account account) { return hash160(account.getScriptHash()); } /** * Creates a hash160 parameter from the given script hash. * * @param hash a script hash * @return the contract parameter. */ public static ContractParameter hash160(Hash160 hash) { if (hash == null) { throw new IllegalArgumentException("The script hash argument must not be null."); } return new ContractParameter(ContractParameterType.HASH160, hash); } /** * Creates a hash256 parameter from the given hex string. * * @param hashHexString a 256-bit hash in hexadecimal and big-endian order. * @return the contract parameter. */ public static ContractParameter hash256(String hashHexString) { if (!isValidHexString(hashHexString)) { throw new IllegalArgumentException("Argument is not a valid hex number."); } return hash256(hexStringToByteArray(hashHexString)); } /** * Creates a hash256 parameter from the given hash. * * @param hash a 256-bit hash. * @return the contract parameter. */ public static ContractParameter hash256(Hash256 hash) { return new ContractParameter(HASH256, hash); } /** * Creates a hash256 parameter from the given bytes. * * @param hash a 256-bit hash in big-endian order. * @return the contract parameter. */ public static ContractParameter hash256(byte[] hash) { if (hash.length != 32) { throw new IllegalArgumentException("A Hash256 parameter must be 32 bytes but was " + hash.length + " bytes."); } return hash256(new Hash256(hash)); } /** * Creates a public key parameter from the given public key. *

* The public key must be encoded in compressed format as described in section 2.3.3 of * SEC1. * * @param publicKey the public key in hexadecimal representation. * @return the contract parameter. */ public static ContractParameter publicKey(String publicKey) { return publicKey(hexStringToByteArray(publicKey)); } /** * Creates a public key parameter from the given public key bytes. *

* The public key must be encoded in compressed format as described in section 2.3.3 of * SEC1. * * @param publicKey the public key to use in the parameter. * @return the contract parameter. */ public static ContractParameter publicKey(byte[] publicKey) { if (publicKey.length != NeoConstants.PUBLIC_KEY_SIZE) { throw new IllegalArgumentException("Public key argument must be " + NeoConstants.PUBLIC_KEY_SIZE + " bytes but was " + publicKey.length + " bytes."); } return new ContractParameter(ContractParameterType.PUBLIC_KEY, publicKey); } public String getParamName() { return paramName; } public ContractParameterType getParamType() { return paramType; } public Object getValue() { return value; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof ContractParameter)) { return false; } ContractParameter that = (ContractParameter) o; if (paramType == that.paramType && Objects.equals(paramName, that.paramName)) { if (paramType.equals(ContractParameterType.BYTE_ARRAY) || paramType.equals(ContractParameterType.SIGNATURE) || paramType.equals(ContractParameterType.PUBLIC_KEY) || paramType.equals(ContractParameterType.HASH160) || paramType.equals(ContractParameterType.HASH256)) { return Arrays.equals((byte[]) value, (byte[]) that.value); } else if (paramType.equals(ContractParameterType.ARRAY)) { ContractParameter[] thatValue = (ContractParameter[]) that.getValue(); ContractParameter[] oValue = (ContractParameter[]) ((ContractParameter) o).getValue(); return Arrays.equals(oValue, thatValue); } else { return Objects.equals(value, that.value); } } else { return false; } } @Override public int hashCode() { return Objects.hash(paramName, paramType, value); } protected static class ContractParameterSerializer extends StdSerializer { public ContractParameterSerializer() { this(null); } public ContractParameterSerializer(Class vc) { super(vc); } @Override public void serialize(ContractParameter value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeStartObject(); serializeParameter(value, gen); gen.writeEndObject(); } private void serializeParameter(ContractParameter p, JsonGenerator gen) throws IOException { if (p.getParamName() != null) { gen.writeStringField("name", p.getParamName()); } if (p.getParamType() != null) { gen.writeStringField("type", p.getParamType().jsonValue()); } if (p.getValue() != null) { serializeValue(p, gen); } } private void serializeValue(ContractParameter p, JsonGenerator gen) throws IOException { switch (p.getParamType()) { case SIGNATURE: case PUBLIC_KEY: // Here we expect a simple byte array which is converted to a hex string. The // byte order is not changed. gen.writeStringField("value", toHexStringNoPrefix((byte[]) p.getValue())); break; case BYTE_ARRAY: gen.writeStringField("value", Base64.encode((byte[]) p.getValue())); break; case BOOLEAN: // Convert to true or false without quotes gen.writeBooleanField("value", (boolean) p.getValue()); break; case INTEGER: // Convert to a string, i.e. in the final json the number has quotes around it. case HASH256: case HASH160: // In case of a hash, the toString() method returns a big-endian hex string. case INTEROP_INTERFACE: // We assume that the interop interface parameter holds a plain string. case STRING: gen.writeStringField("value", p.getValue().toString()); break; case ARRAY: gen.writeArrayFieldStart("value"); for (final ContractParameter param : (ContractParameter[]) p.getValue()) { gen.writeStartObject(); serializeParameter(param, gen); gen.writeEndObject(); } gen.writeEndArray(); break; case MAP: gen.writeArrayFieldStart("value"); HashMap map = (HashMap) p.getValue(); for (final ContractParameter key : map.keySet()) { gen.writeStartObject(); gen.writeFieldName("key"); gen.writeStartObject(); serializeParameter(key, gen); gen.writeEndObject(); gen.writeFieldName("value"); gen.writeStartObject(); serializeParameter(map.get(key), gen); gen.writeEndObject(); gen.writeEndObject(); } gen.writeEndArray(); break; default: throw new UnsupportedOperationException("Parameter type '" + p.getParamType().toString() + "' not supported."); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy