From c503a2b882a32ce70acd74d0ff1d46d195b3e88f Mon Sep 17 00:00:00 2001 From: Ezra Epstein <ezra_epstein@yahoo.com> Date: Wed, 8 Nov 2017 21:10:25 -0800 Subject: [PATCH] Support for generating Java source from Truffle .json contract files. --- .../codegen/FunctionWrapperGenerator.java | 69 + .../codegen/SolidityFunctionWrapper.java | 53 +- .../SolidityFunctionWrapperGenerator.java | 61 +- .../TruffleJsonFunctionWrapperGenerator.java | 480 ++++++ .../web3j/codegen/ContractJsonParseTest.java | 68 + .../SolidityFunctionWrapperGeneratorTest.java | 1 - ...uffleJsonFunctionWrapperGeneratorTest.java | 101 ++ .../resources/truffle/MetaCoin/ConvertLib.sol | 8 + .../resources/truffle/MetaCoin/MetaCoin.sol | 34 + .../MetaCoin/build/contracts/ConvertLib.json | 281 ++++ .../MetaCoin/build/contracts/MetaCoin.json | 1431 +++++++++++++++++ .../main/java/org/web3j/console/Runner.java | 4 + .../core/methods/response/AbiDefinition.java | 40 + core/src/main/java/org/web3j/tx/Contract.java | 30 + .../main/java/org/web3j/utils/Strings.java | 4 + 15 files changed, 2612 insertions(+), 53 deletions(-) create mode 100644 codegen/src/main/java/org/web3j/codegen/FunctionWrapperGenerator.java create mode 100644 codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java create mode 100644 codegen/src/test/java/org/web3j/codegen/ContractJsonParseTest.java create mode 100644 codegen/src/test/java/org/web3j/codegen/TruffleJsonFunctionWrapperGeneratorTest.java create mode 100644 codegen/src/test/resources/truffle/MetaCoin/ConvertLib.sol create mode 100644 codegen/src/test/resources/truffle/MetaCoin/MetaCoin.sol create mode 100644 codegen/src/test/resources/truffle/MetaCoin/build/contracts/ConvertLib.json create mode 100644 codegen/src/test/resources/truffle/MetaCoin/build/contracts/MetaCoin.json diff --git a/codegen/src/main/java/org/web3j/codegen/FunctionWrapperGenerator.java b/codegen/src/main/java/org/web3j/codegen/FunctionWrapperGenerator.java new file mode 100644 index 000000000..4314f2e2a --- /dev/null +++ b/codegen/src/main/java/org/web3j/codegen/FunctionWrapperGenerator.java @@ -0,0 +1,69 @@ +package org.web3j.codegen; + +import java.io.File; + +import static org.web3j.codegen.Console.exitError; + +/** + * Abstract base class for the concrete function wrapper generators. + */ +abstract class FunctionWrapperGenerator { + + static final String JAVA_TYPES_ARG = "--javaTypes"; + static final String SOLIDITY_TYPES_ARG = "--solidityTypes"; + + final File destinationDirLocation; + final String basePackageName; + final boolean useJavaNativeTypes; + + FunctionWrapperGenerator( + String destinationDirLocation, + String basePackageName, + boolean useJavaNativeTypes) { + + this.destinationDirLocation = new File(destinationDirLocation); + this.basePackageName = basePackageName; + this.useJavaNativeTypes = useJavaNativeTypes; + } + + static boolean useJavaNativeTypes(String argVal, String usageString) { + boolean useJavaNativeTypes = true; + if (SOLIDITY_TYPES_ARG.equals(argVal)) { + useJavaNativeTypes = false; + } else if (JAVA_TYPES_ARG.equals(argVal)) { + useJavaNativeTypes = true; + } else { + exitError(usageString); + } + return useJavaNativeTypes; + } + + static String parsePositionalArg(String[] args, int idx) { + if (args != null && args.length > idx) { + return args[idx]; + } else { + return ""; + } + } + + static String parseParameterArgument(String[] args, String... parameters) { + for (String parameter : parameters) { + for (int i = 0; i < args.length; i++) { + if (args[i].equals(parameter) + && i + 1 < args.length) { + String parameterValue = args[i + 1]; + if (!parameterValue.startsWith("-")) { + return parameterValue; + } + } + } + } + return ""; + } + + static String getFileNameNoExtension(String fileName) { + String[] splitName = fileName.split("\\.(?=[^.]*$)"); + return splitName[0]; + } + +} diff --git a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java index dd5ac96c8..1021ca6bb 100644 --- a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java +++ b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java @@ -5,7 +5,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; import javax.lang.model.element.Modifier; @@ -81,10 +83,21 @@ public SolidityFunctionWrapper(boolean useNativeJavaTypes) { this.useNativeJavaTypes = useNativeJavaTypes; } + @SuppressWarnings("unchecked") public void generateJavaFiles( String contractName, String bin, String abi, String destinationDir, String basePackageName) throws IOException, ClassNotFoundException { + generateJavaFiles(contractName, bin, + loadContractDefinition(abi), + destinationDir, basePackageName, + null); + } + + void generateJavaFiles( + String contractName, String bin, List<AbiDefinition> abi, String destinationDir, + String basePackageName, Map<String, String> addresses) + throws IOException, ClassNotFoundException { String className = Strings.capitaliseFirstLetter(contractName); TypeSpec.Builder classBuilder = createClassBuilder(className, bin); @@ -92,13 +105,51 @@ public void generateJavaFiles( classBuilder.addMethod(buildConstructor(Credentials.class, CREDENTIALS)); classBuilder.addMethod(buildConstructor(TransactionManager.class, TRANSACTION_MANAGER)); classBuilder.addMethods( - buildFunctionDefinitions(className, classBuilder, loadContractDefinition(abi))); + buildFunctionDefinitions(className, classBuilder, abi)); classBuilder.addMethod(buildLoad(className, Credentials.class, CREDENTIALS)); classBuilder.addMethod(buildLoad(className, TransactionManager.class, TRANSACTION_MANAGER)); + addAddressesSupport(classBuilder, addresses); + write(basePackageName, classBuilder.build(), destinationDir); } + private void addAddressesSupport(TypeSpec.Builder classBuilder, Map<String, String> addresses) { + if (addresses != null) { + + ClassName stringType = ClassName.get(String.class); + ClassName mapType = ClassName.get(HashMap.class); + TypeName mapStringString = ParameterizedTypeName.get(mapType, stringType, stringType); + FieldSpec addressesStaticField = FieldSpec + .builder(mapStringString, "_addresses", + Modifier.PROTECTED, Modifier.STATIC, Modifier.FINAL) + .build(); + classBuilder.addField(addressesStaticField); + + final CodeBlock.Builder staticInit = CodeBlock.builder(); + staticInit.addStatement("_addresses = new HashMap<>()"); + addresses.forEach((k, v) -> + staticInit.addStatement(String.format("_addresses.put(\"%1s\", \"%2s\")", k, v)) + ); + classBuilder.addStaticBlock(staticInit.build()); + + // See org.web3j.tx.Contract#getStaticDeployedAddress(String) + MethodSpec getAddress = MethodSpec + .methodBuilder("getStaticDeployedAddress") + .addModifiers(Modifier.PROTECTED) + .returns(stringType) + .addParameter(stringType, "networkId") + .addCode(CodeBlock + .builder() + .addStatement("return _addresses.get(networkId)") + .build()) + .build(); + classBuilder.addMethod(getAddress); + + } + } + + private TypeSpec.Builder createClassBuilder(String className, String binary) { String javadoc = CODEGEN_WARNING + getWeb3jVersion(); diff --git a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapperGenerator.java b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapperGenerator.java index cd0ec1d95..7716578ec 100644 --- a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapperGenerator.java +++ b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapperGenerator.java @@ -18,7 +18,7 @@ /** * Java wrapper source code generator for Solidity ABI format. */ -public class SolidityFunctionWrapperGenerator { +public class SolidityFunctionWrapperGenerator extends FunctionWrapperGenerator { private static final String USAGE = "solidity generate " + "[--javaTypes|--solidityTypes] " @@ -26,14 +26,8 @@ public class SolidityFunctionWrapperGenerator { + "-p|--package <base package name> " + "-o|--output <destination base directory>"; - static final String JAVA_TYPES_ARG = "--javaTypes"; - static final String SOLIDITY_TYPES_ARG = "--solidityTypes"; - - private String binaryFileLocation; - private String absFileLocation; - private File destinationDirLocation; - private String basePackageName; - private boolean useJavaNativeTypes; + private final String binaryFileLocation; + private final String absFileLocation; private SolidityFunctionWrapperGenerator( String binaryFileLocation, @@ -42,11 +36,9 @@ private SolidityFunctionWrapperGenerator( String basePackageName, boolean useJavaNativeTypes) { + super(destinationDirLocation, basePackageName, useJavaNativeTypes); this.binaryFileLocation = binaryFileLocation; this.absFileLocation = absFileLocation; - this.destinationDirLocation = new File(destinationDirLocation); - this.basePackageName = basePackageName; - this.useJavaNativeTypes = useJavaNativeTypes; } public static void run(String[] args) throws Exception { @@ -72,14 +64,7 @@ public static void main(String[] args) throws Exception { exitError(USAGE); } - boolean useJavaNativeTypes = true; - if (fullArgs[0].equals(SOLIDITY_TYPES_ARG)) { - useJavaNativeTypes = false; - } else if (fullArgs[0].equals(JAVA_TYPES_ARG)) { - useJavaNativeTypes = true; - } else { - exitError(USAGE); - } + boolean useJavaNativeTypes = useJavaNativeTypes(fullArgs[0], USAGE); String binaryFileLocation = parsePositionalArg(fullArgs, 1); String absFileLocation = parsePositionalArg(fullArgs, 2); @@ -102,27 +87,11 @@ public static void main(String[] args) throws Exception { .generate(); } - private static String parsePositionalArg(String[] args, int idx) { - if (args != null && args.length > idx) { - return args[idx]; - } else { - return ""; - } - } - - private static String parseParameterArgument(String[] args, String... parameters) { - for (String parameter : parameters) { - for (int i = 0; i < args.length; i++) { - if (args[i].equals(parameter) - && i + 1 < args.length) { - String parameterValue = args[i + 1]; - if (!parameterValue.startsWith("-")) { - return parameterValue; - } - } - } - } - return ""; + static List<AbiDefinition> loadContractDefinition(File absFile) + throws IOException { + ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + AbiDefinition[] abiDefinition = objectMapper.readValue(absFile, AbiDefinition[].class); + return Arrays.asList(abiDefinition); } private void generate() throws IOException, ClassNotFoundException { @@ -157,15 +126,5 @@ private void generate() throws IOException, ClassNotFoundException { } } - private static List<AbiDefinition> loadContractDefinition(File absFile) - throws IOException { - ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); - AbiDefinition[] abiDefinition = objectMapper.readValue(absFile, AbiDefinition[].class); - return Arrays.asList(abiDefinition); - } - static String getFileNameNoExtension(String fileName) { - String[] splitName = fileName.split("\\.(?=[^.]*$)"); - return splitName[0]; - } } \ No newline at end of file diff --git a/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java b/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java new file mode 100644 index 000000000..bbeba6d83 --- /dev/null +++ b/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java @@ -0,0 +1,480 @@ +package org.web3j.codegen; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.web3j.protocol.ObjectMapperFactory; +import org.web3j.protocol.core.methods.response.AbiDefinition; +import org.web3j.utils.Strings; + +import static org.web3j.codegen.Console.exitError; +import static org.web3j.utils.Collection.tail; + +/** + * Java wrapper source code generator for Truffle JSON format. Truffle embeds the Solidity ABI + * formatted JSON in its own format. That format also gives access to the binary code. It also + * contains information about deployment addresses. This should make integration with Truffle + * easier. + */ +public class TruffleJsonFunctionWrapperGenerator extends FunctionWrapperGenerator { + + private static final String USAGE = "truffle generate " + + "[--javaTypes|--solidityTypes] " + + "<input truffle json file>.json " + + "-p|--package <base package name> " + + "-o|--output <destination base directory>"; + + + private String jsonFileLocation; + + private TruffleJsonFunctionWrapperGenerator( + String jsonFileLocation, + String destinationDirLocation, + String basePackageName, + boolean useJavaNativeTypes) { + + super(destinationDirLocation, basePackageName, useJavaNativeTypes); + this.jsonFileLocation = jsonFileLocation; + } + + public static void run(String[] args) throws Exception { + if (args.length < 1 || !"generate".equals(args[0])) { + exitError(USAGE); + } else { + main(tail(args)); + } + } + + public static void main(String[] args) throws Exception { + + String[] fullArgs; + if (args.length == 5) { + fullArgs = new String[args.length + 1]; + fullArgs[0] = JAVA_TYPES_ARG; + System.arraycopy(args, 0, fullArgs, 1, args.length); + } else { + fullArgs = args; + } + + if (fullArgs.length != 6) { + exitError(USAGE); + } + + boolean useJavaNativeTypes = useJavaNativeTypes(fullArgs[0], USAGE); + + String jsonFileLocation = parsePositionalArg(fullArgs, 1); + String destinationDirLocation = parseParameterArgument(fullArgs, "-o", "--outputDir"); + String basePackageName = parseParameterArgument(fullArgs, "-p", "--package"); + + if (Strings.isEmpty(jsonFileLocation) + || Strings.isEmpty(destinationDirLocation) + || Strings.isEmpty(basePackageName)) { + exitError(USAGE); + } + + new TruffleJsonFunctionWrapperGenerator( + jsonFileLocation, + destinationDirLocation, + basePackageName, + useJavaNativeTypes) + .generate(); + } + + static Contract loadContractDefinition(File jsonFile) + throws IOException { + ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); + return objectMapper.readValue(jsonFile, Contract.class); + } + + @SuppressWarnings("unchecked") + private void generate() throws IOException, ClassNotFoundException { + + File truffleJsonFile = new File(jsonFileLocation); + if (!truffleJsonFile.exists() || !truffleJsonFile.canRead()) { + exitError("Invalid input json file specified: " + jsonFileLocation); + } + + String fileName = truffleJsonFile.getName(); + String contractName = getFileNameNoExtension(fileName); + + Contract c = loadContractDefinition(truffleJsonFile); + if (c == null) { + exitError("Unable to parse input json file"); + } else { + String className = Strings.capitaliseFirstLetter(contractName); + System.out.printf("Generating " + basePackageName + "." + className + " ... "); + Map<String, String> addresses; + if (c.networks != null && !c.networks.isEmpty()) { + addresses = c.networks.entrySet().stream().collect(Collectors.toMap( + Map.Entry::getKey, e -> e.getValue().getAddress() + )); + } else { + addresses = Collections.EMPTY_MAP; + } + new SolidityFunctionWrapper(useJavaNativeTypes) + .generateJavaFiles(contractName, + c.bytecode, + c.abi, + destinationDirLocation.toString(), + basePackageName, + addresses); + System.out.println("File written to " + destinationDirLocation.toString() + "\n"); + } + } + + /** + * Truffle Contract <p> Describes a contract exported by and consumable by Truffle, which may + * include information about deployed instances on networks. </p> + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonPropertyOrder({ + "contractName", + "abi", + "bytecode", + "deployedBytecode", + "sourceMap", + "deployedSourceMap", + "source", + "sourcePath", + "ast", + "compiler", + "networks", + "schemaVersion", + "updatedAt" + }) + public static class Contract { + + @JsonProperty("contractName") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "^[a-zA-Z_][a-zA-Z0-9_]*$") + public String contractName; + @JsonProperty(value = "abi", required = true) + public List<AbiDefinition> abi; + @JsonProperty("bytecode") + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "^0x0$|^0x([a-fA-F0-9]{2}|__.{38})+$") + public String bytecode; + @JsonProperty("deployedBytecode") + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "^0x0$|^0x([a-fA-F0-9]{2}|__.{38})+$") + public String deployedBytecode; + @JsonProperty("sourceMap") + public String sourceMap; + @JsonProperty("deployedSourceMap") + public String deployedSourceMap; + @JsonProperty("source") + public String source; + @JsonProperty("sourcePath") + public String sourcePath; + @JsonProperty("ast") + public JsonNode ast; + @JsonProperty("compiler") + public Compiler compiler; + @JsonProperty("networks") + public Map<String, NetworkInfo> networks; + @JsonProperty("schemaVersion") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "[0-9]+\\.[0-9]+\\.[0-9]+") + public String schemaVersion; + @JsonProperty("updatedAt") + @JsonFormat(shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "GMT") + public Date updatedAt; + + /** + * No args constructor for use in serialization. + */ + public Contract() { + } + + /** + * Default constructor. + */ + public Contract(String contractName, List<AbiDefinition> abi, String bytecode, + String deployedBytecode, + String sourceMap, String deployedSourceMap, String source, String sourcePath, + JsonNode ast, + Compiler compiler, Map<String, NetworkInfo> networks, String schemaVersion, + Date updatedAt) { + super(); + this.contractName = contractName; + this.abi = abi; + this.bytecode = bytecode; + this.deployedBytecode = deployedBytecode; + this.sourceMap = sourceMap; + this.deployedSourceMap = deployedSourceMap; + this.source = source; + this.sourcePath = sourcePath; + this.ast = ast; + this.compiler = compiler; + this.networks = networks; + this.schemaVersion = schemaVersion; + this.updatedAt = updatedAt; + } + + public Contract withContractName(String contractName) { + this.contractName = contractName; + return this; + } + + public Contract withAbi(List<AbiDefinition> abi) { + this.abi = abi; + return this; + } + + public Contract withBytecode(String bytecode) { + this.bytecode = bytecode; + return this; + } + + public Contract withDeployedBytecode(String deployedBytecode) { + this.deployedBytecode = deployedBytecode; + return this; + } + + public Contract withSourceMap(String sourceMap) { + this.sourceMap = sourceMap; + return this; + } + + public Contract withDeployedSourceMap(String deployedSourceMap) { + this.deployedSourceMap = deployedSourceMap; + return this; + } + + public Contract withSource(String source) { + this.source = source; + return this; + } + + public Contract withSourcePath(String sourcePath) { + this.sourcePath = sourcePath; + return this; + } + + public Contract withAst(JsonNode ast) { + this.ast = ast; + return this; + } + + public Contract withCompiler(Compiler compiler) { + this.compiler = compiler; + return this; + } + + public Contract withNetworks(Map<String, NetworkInfo> networks) { + this.networks = networks; + return this; + } + + public Contract withSchemaVersion(String schemaVersion) { + this.schemaVersion = schemaVersion; + return this; + } + + public Contract withUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + return this; + } + + public String getContractName() { + return contractName; + } + + public List<AbiDefinition> getAbi() { + return abi; + } + + public String getBytecode() { + return bytecode; + } + + public String getDeployedBytecode() { + return deployedBytecode; + } + + public String getSourceMap() { + return sourceMap; + } + + public String getDeployedSourceMap() { + return deployedSourceMap; + } + + public String getSource() { + return source; + } + + public String getSourcePath() { + return sourcePath; + } + + public JsonNode getAst() { + return ast; + } + + public Compiler getCompiler() { + return compiler; + } + + public Map<String, NetworkInfo> getNetworks() { + return networks; + } + + public String getSchemaVersion() { + return schemaVersion; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public NetworkInfo getNetwork(String networkId) { + return networks.get(networkId); + } + + public String getAddress(String networkId) { + NetworkInfo network = getNetwork(networkId); + return network == null ? null : network.getAddress(); + } + + /** + * Convenience method to get the deployed address of the contract. + * + * @param network the contract's address on this Ethereum network + * @return the contract's address or <code>null</code> if there isn't one known. + */ + public String getAddress(Network network) { + return getAddress(Long.toString(network.id)); + } + + enum Network { + olympic(0), mainnet(1), morden(2), ropsten(3), rinkeby(4), kovan(42); + + public final long id; + + Network(long id) { + this.id = id; + } + } + + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonPropertyOrder({ + "name", + "version" + }) + public static class Compiler { + + @JsonProperty("name") + public String name; + @JsonProperty("version") + public String version; + @JsonIgnore + private Map<String, JsonNode> additionalProperties = new HashMap<String, JsonNode>(); + + /** + * No args constructor for use in serialization. + */ + public Compiler() { + } + + /** + * Default constructor. + */ + public Compiler(String name, String version) { + super(); + this.name = name; + this.version = version; + } + + public Compiler withName(String name) { + this.name = name; + return this; + } + + public Compiler withVersion(String version) { + this.version = version; + return this; + } + + @JsonAnyGetter + public Map<String, JsonNode> getAdditionalProperties() { + return this.additionalProperties; + } + + @JsonAnySetter + public void setAdditionalProperty(String name, JsonNode value) { + this.additionalProperties.put(name, value); + } + + public Compiler withAdditionalProperty(String name, JsonNode value) { + this.additionalProperties.put(name, value); + return this; + } + + } + + + // For now we just ignore "events" + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + @JsonPropertyOrder({ + "events", + "links", + "address" + }) + public static class NetworkInfo { + + @JsonProperty("events") + public Map<String, JsonNode> events; + @JsonProperty("links") + public Map<String, JsonNode> links; + @JsonProperty("address") + public String address; + + /** + * No args constructor for use in serialization. + */ + public NetworkInfo() { + } + + public NetworkInfo(Map<String, JsonNode> events, Map<String, JsonNode> links, + String address) { + super(); + this.events = events; + this.links = links; + this.address = address; + } + + public NetworkInfo withAddress(String address) { + this.address = address; + return this; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + } + +} \ No newline at end of file diff --git a/codegen/src/test/java/org/web3j/codegen/ContractJsonParseTest.java b/codegen/src/test/java/org/web3j/codegen/ContractJsonParseTest.java new file mode 100644 index 000000000..e345c7849 --- /dev/null +++ b/codegen/src/test/java/org/web3j/codegen/ContractJsonParseTest.java @@ -0,0 +1,68 @@ +package org.web3j.codegen; + +import java.io.File; +import java.net.URL; + +import org.junit.Before; +import org.junit.Test; + +import org.web3j.protocol.core.methods.response.AbiDefinition; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.web3j.codegen.TruffleJsonFunctionWrapperGenerator.Contract; +import static org.web3j.codegen.TruffleJsonFunctionWrapperGenerator.loadContractDefinition; + +/** + * Test that we can parse Truffle Contract from JSON file. + */ +public class ContractJsonParseTest { + + static final String BUILD_CONTRACTS = "build" + File.separator + "contracts"; + private String contractBaseDir; + + static String jsonFileLocation(String baseDir, + String contractName, String inputFileName) { + return baseDir + File.separator + contractName + File.separator + BUILD_CONTRACTS + + File.separator + inputFileName + ".json"; + } + + @SuppressWarnings("SameParameterValue") + static Contract parseContractJson(String baseDir, + String contractName, String inputFileName) + throws Exception { + + String fileLocation = jsonFileLocation(baseDir, contractName, inputFileName); + return loadContractDefinition(new File(fileLocation)); + } + + @Before + public void setUp() throws Exception { + URL url = SolidityFunctionWrapperGeneratorTest.class.getClass().getResource("/truffle"); + contractBaseDir = url.getPath(); + } + + @Test + public void testParseMetaCoin() throws Exception { + Contract mc = parseContractJson(contractBaseDir, "MetaCoin", "MetaCoin"); + + assertEquals("Unexpected contract name", "MetaCoin", mc.getContractName()); + } + + @Test + public void testParseConvertLib() throws Exception { + Contract mc = parseContractJson(contractBaseDir, "MetaCoin", "ConvertLib"); + + assertEquals("Unexpected contract name", "ConvertLib", mc.getContractName()); + assertEquals("Unexpected number of functions", 1, mc.abi.size()); + AbiDefinition abi = mc.abi.get(0); + assertEquals("Unexpected function name", "convert", abi.getName()); + assertTrue("Expected function to be 'constant'", abi.isConstant()); + assertFalse("Expected function to not be 'payable'", abi.isPayable()); + assertEquals("Expected abi to represent a function", "function", abi.getType()); + assertEquals("Expected the 'pure' for the state mutability setting", "pure", + abi.getStateMutability()); + + } +} \ No newline at end of file diff --git a/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java b/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java index d899c903c..966a192ea 100644 --- a/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java +++ b/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.net.URL; import java.util.Arrays; -import java.util.Collections; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; diff --git a/codegen/src/test/java/org/web3j/codegen/TruffleJsonFunctionWrapperGeneratorTest.java b/codegen/src/test/java/org/web3j/codegen/TruffleJsonFunctionWrapperGeneratorTest.java new file mode 100644 index 000000000..008d36dd6 --- /dev/null +++ b/codegen/src/test/java/org/web3j/codegen/TruffleJsonFunctionWrapperGeneratorTest.java @@ -0,0 +1,101 @@ +package org.web3j.codegen; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.Collections; + +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import org.junit.Before; +import org.junit.Test; + +import org.web3j.TempFileProvider; +import org.web3j.utils.Strings; + +import static org.junit.Assert.assertTrue; +import static org.web3j.codegen.FunctionWrapperGenerator.JAVA_TYPES_ARG; +import static org.web3j.codegen.FunctionWrapperGenerator.SOLIDITY_TYPES_ARG; + +public class TruffleJsonFunctionWrapperGeneratorTest extends TempFileProvider { + + private static final String PackageName = "org.web3j.unittests.truffle.java"; + + private String contractBaseDir; + + private static void verifyGeneratedCode(String sourceFile) throws IOException { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); + + try (StandardJavaFileManager fileManager = + compiler.getStandardFileManager(diagnostics, null, null)) { + Iterable<? extends JavaFileObject> compilationUnits = fileManager + .getJavaFileObjectsFromStrings(Collections.singletonList(sourceFile)); + JavaCompiler.CompilationTask task = compiler.getTask( + null, fileManager, diagnostics, null, null, compilationUnits); + assertTrue("Generated contract contains compile time error", task.call()); + } + } + + @Before + public void setUp() throws Exception { + super.setUp(); + + URL url = SolidityFunctionWrapperGeneratorTest.class.getClass().getResource("/truffle"); + contractBaseDir = url.getPath(); + } + + @Test + public void testLibGeneration() throws Exception { + testCodeGenerationJvmTypes("MetaCoin", "ConvertLib"); + testCodeGenerationSolidtyTypes("MetaCoin", "ConvertLib"); + } + + @Test + public void testContractGeneration() throws Exception { + testCodeGenerationJvmTypes("MetaCoin", "MetaCoin"); + testCodeGenerationSolidtyTypes("MetaCoin", "MetaCoin"); + } + + @SuppressWarnings("SameParameterValue") + private void testCodeGenerationJvmTypes( + String contractName, String inputFileName) throws Exception { + + testCodeGeneration( + contractName, inputFileName, PackageName, JAVA_TYPES_ARG); + + } + + @SuppressWarnings("SameParameterValue") + private void testCodeGenerationSolidtyTypes( + String contractName, String inputFileName) throws Exception { + + testCodeGeneration( + contractName, inputFileName, PackageName, SOLIDITY_TYPES_ARG); + + } + + private void testCodeGeneration( + String contractName, String inputFileName, String packageName, String types) + throws Exception { + + TruffleJsonFunctionWrapperGenerator.main(Arrays.asList( + types, + ContractJsonParseTest + .jsonFileLocation(contractBaseDir, contractName, inputFileName), + "-p", packageName, + "-o", tempDirPath + ).toArray(new String[0])); + + verifyGeneratedCode(tempDirPath + File.separator + + packageName.replace('.', File.separatorChar) + File.separator + + Strings.capitaliseFirstLetter(inputFileName) + ".java"); + } + + +} \ No newline at end of file diff --git a/codegen/src/test/resources/truffle/MetaCoin/ConvertLib.sol b/codegen/src/test/resources/truffle/MetaCoin/ConvertLib.sol new file mode 100644 index 000000000..99f004dfe --- /dev/null +++ b/codegen/src/test/resources/truffle/MetaCoin/ConvertLib.sol @@ -0,0 +1,8 @@ +pragma solidity ^0.4.2; + +library ConvertLib{ + function convert(uint amount,uint conversionRate) pure public returns (uint convertedAmount) + { + return amount * conversionRate; + } +} diff --git a/codegen/src/test/resources/truffle/MetaCoin/MetaCoin.sol b/codegen/src/test/resources/truffle/MetaCoin/MetaCoin.sol new file mode 100644 index 000000000..2658d0466 --- /dev/null +++ b/codegen/src/test/resources/truffle/MetaCoin/MetaCoin.sol @@ -0,0 +1,34 @@ +pragma solidity ^0.4.2; + +import "./ConvertLib.sol"; + +// This is just a simple example of a coin-like contract. +// It is not standards compatible and cannot be expected to talk to other +// coin/token contracts. If you want to create a standards-compliant +// token, see: https://github.com/ConsenSys/Tokens. Cheers! + +contract MetaCoin { + mapping (address => uint) balances; + + event Transfer(address indexed _from, address indexed _to, uint256 _value); + + function MetaCoin() public { + balances[tx.origin] = 10000; + } + + function sendCoin(address receiver, uint amount) public returns(bool sufficient) { + if (balances[msg.sender] < amount) return false; + balances[msg.sender] -= amount; + balances[receiver] += amount; + Transfer(msg.sender, receiver, amount); + return true; + } + + function getBalanceInEth(address addr) view public returns(uint){ + return ConvertLib.convert(getBalance(addr),2); + } + + function getBalance(address addr) view public returns(uint) { + return balances[addr]; + } +} diff --git a/codegen/src/test/resources/truffle/MetaCoin/build/contracts/ConvertLib.json b/codegen/src/test/resources/truffle/MetaCoin/build/contracts/ConvertLib.json new file mode 100644 index 000000000..a54254200 --- /dev/null +++ b/codegen/src/test/resources/truffle/MetaCoin/build/contracts/ConvertLib.json @@ -0,0 +1,281 @@ +{ + "contractName": "ConvertLib", + "abi": [ + { + "constant": true, + "inputs": [ + { + "name": "amount", + "type": "uint256" + }, + { + "name": "conversionRate", + "type": "uint256" + } + ], + "name": "convert", + "outputs": [ + { + "name": "convertedAmount", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + } + ], + "bytecode": "0x6060604052341561000f57600080fd5b60b08061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806396e4ee3d146044575b600080fd5b606160048080359060200190919080359060200190919050506077565b6040518082815260200191505060405180910390f35b60008183029050929150505600a165627a7a72305820fc2416f7929b800f6d4af1a1e6d2a8d7d8ac81998f8c072a99314c7bf5c2a5f80029", + "deployedBytecode": "0x606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806396e4ee3d146044575b600080fd5b606160048080359060200190919080359060200190919050506077565b6040518082815260200191505060405180910390f35b60008183029050929150505600a165627a7a72305820fc2416f7929b800f6d4af1a1e6d2a8d7d8ac81998f8c072a99314c7bf5c2a5f80029", + "sourceMap": "25:155:0:-;;;;;;;;;;;;;;;;;", + "deployedSourceMap": "25:155:0:-;;;;;;;;;;;;;;;;;;;;;;;;46:132;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;117:20;160:14;151:6;:23;144:30;;46:132;;;;:::o", + "source": "pragma solidity ^0.4.2;\n\nlibrary ConvertLib{\n\tfunction convert(uint amount,uint conversionRate) pure public returns (uint convertedAmount)\n\t{\n\t\treturn amount * conversionRate;\n\t}\n}\n", + "sourcePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/ConvertLib.sol", + "ast": { + "attributes": { + "absolutePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/ConvertLib.sol", + "exportedSymbols": { + "ConvertLib": [ + 16 + ] + } + }, + "children": [ + { + "attributes": { + "literals": [ + "solidity", + "^", + "0.4", + ".2" + ] + }, + "id": 1, + "name": "PragmaDirective", + "src": "0:23:0" + }, + { + "attributes": { + "baseContracts": [ + null + ], + "contractDependencies": [ + null + ], + "contractKind": "library", + "documentation": null, + "fullyImplemented": true, + "linearizedBaseContracts": [ + 16 + ], + "name": "ConvertLib", + "scope": 17 + }, + "children": [ + { + "attributes": { + "constant": true, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "convert", + "payable": false, + "scope": 16, + "stateMutability": "pure", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "amount", + "scope": 15, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 2, + "name": "ElementaryTypeName", + "src": "63:4:0" + } + ], + "id": 3, + "name": "VariableDeclaration", + "src": "63:11:0" + }, + { + "attributes": { + "constant": false, + "name": "conversionRate", + "scope": 15, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 4, + "name": "ElementaryTypeName", + "src": "75:4:0" + } + ], + "id": 5, + "name": "VariableDeclaration", + "src": "75:19:0" + } + ], + "id": 6, + "name": "ParameterList", + "src": "62:33:0" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "convertedAmount", + "scope": 15, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 7, + "name": "ElementaryTypeName", + "src": "117:4:0" + } + ], + "id": 8, + "name": "VariableDeclaration", + "src": "117:20:0" + } + ], + "id": 9, + "name": "ParameterList", + "src": "116:22:0" + }, + { + "children": [ + { + "attributes": { + "functionReturnParameters": 9 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "*", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 3, + "type": "uint256", + "value": "amount" + }, + "id": 10, + "name": "Identifier", + "src": "151:6:0" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5, + "type": "uint256", + "value": "conversionRate" + }, + "id": 11, + "name": "Identifier", + "src": "160:14:0" + } + ], + "id": 12, + "name": "BinaryOperation", + "src": "151:23:0" + } + ], + "id": 13, + "name": "Return", + "src": "144:30:0" + } + ], + "id": 14, + "name": "Block", + "src": "140:38:0" + } + ], + "id": 15, + "name": "FunctionDefinition", + "src": "46:132:0" + } + ], + "id": 16, + "name": "ContractDefinition", + "src": "25:155:0" + } + ], + "id": 17, + "name": "SourceUnit", + "src": "0:181:0" + }, + "compiler": { + "name": "solc", + "version": "0.4.18+commit.9cf6e910.Emscripten.clang" + }, + "networks": { + "4": { + "events": {}, + "links": {}, + "address": "0x14d00a701a2f0d4d65eebaf191f4f60bbaa1da36" + }, + "4447": { + "events": {}, + "links": {}, + "address": "0xcfeb869f69431e42cdb54a4f4f105c19c080a601" + } + }, + "schemaVersion": "1.0.1", + "updatedAt": "2017-11-07T20:44:02.301Z" +} \ No newline at end of file diff --git a/codegen/src/test/resources/truffle/MetaCoin/build/contracts/MetaCoin.json b/codegen/src/test/resources/truffle/MetaCoin/build/contracts/MetaCoin.json new file mode 100644 index 000000000..8bed99e71 --- /dev/null +++ b/codegen/src/test/resources/truffle/MetaCoin/build/contracts/MetaCoin.json @@ -0,0 +1,1431 @@ +{ + "contractName": "MetaCoin", + "abi": [ + { + "constant": true, + "inputs": [ + { + "name": "addr", + "type": "address" + } + ], + "name": "getBalanceInEth", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "receiver", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "sendCoin", + "outputs": [ + { + "name": "sufficient", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "addr", + "type": "address" + } + ], + "name": "getBalance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "_from", + "type": "address" + }, + { + "indexed": true, + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "name": "_value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } + ], + "bytecode": "0x6060604052341561000f57600080fd5b6127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506103c5806100636000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637bd703e81461005c57806390b98a11146100a9578063f8b2cb4f14610103575b600080fd5b341561006757600080fd5b610093600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610150565b6040518082815260200191505060405180910390f35b34156100b457600080fd5b6100e9600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101f8565b604051808215151515815260200191505060405180910390f35b341561010e57600080fd5b61013a600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610351565b6040518082815260200191505060405180910390f35b600073__ConvertLib____________________________6396e4ee3d61017584610351565b60026000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808381526020018281526020019250505060206040518083038186803b15156101d657600080fd5b6102c65a03f415156101e757600080fd5b505050604051805190509050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610249576000905061034b565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509190505600a165627a7a72305820f791829bf0c920a6d43123cac9b9894757ddc838c17efbad6d56773d6e3dcf4c0029", + "deployedBytecode": "0x606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637bd703e81461005c57806390b98a11146100a9578063f8b2cb4f14610103575b600080fd5b341561006757600080fd5b610093600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610150565b6040518082815260200191505060405180910390f35b34156100b457600080fd5b6100e9600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101f8565b604051808215151515815260200191505060405180910390f35b341561010e57600080fd5b61013a600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610351565b6040518082815260200191505060405180910390f35b600073__ConvertLib____________________________6396e4ee3d61017584610351565b60026000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808381526020018281526020019250505060206040518083038186803b15156101d657600080fd5b6102c65a03f415156101e757600080fd5b505050604051805190509050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610249576000905061034b565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509190505600a165627a7a72305820f791829bf0c920a6d43123cac9b9894757ddc838c17efbad6d56773d6e3dcf4c0029", + "sourceMap": "315:675:1:-;;;452:62;;;;;;;;505:5;483:8;:19;492:9;483:19;;;;;;;;;;;;;;;:27;;;;315:675;;;;;;", + "deployedSourceMap": "315:675:1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;779:117;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;517:259;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;899:89;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;779:117;838:4;854:10;:18;873:16;884:4;873:10;:16::i;:::-;890:1;854:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;847:45;;779:117;;;:::o;517:259::-;581:15;629:6;606:8;:20;615:10;606:20;;;;;;;;;;;;;;;;:29;602:47;;;644:5;637:12;;;;602:47;677:6;653:8;:20;662:10;653:20;;;;;;;;;;;;;;;;:30;;;;;;;;;;;709:6;687:8;:18;696:8;687:18;;;;;;;;;;;;;;;;:28;;;;;;;;;;;740:8;719:38;;728:10;719:38;;;750:6;719:38;;;;;;;;;;;;;;;;;;768:4;761:11;;517:259;;;;;:::o;899:89::-;953:4;970:8;:14;979:4;970:14;;;;;;;;;;;;;;;;963:21;;899:89;;;:::o", + "source": "pragma solidity ^0.4.2;\n\nimport \"./ConvertLib.sol\";\n\n// This is just a simple example of a coin-like contract.\n// It is not standards compatible and cannot be expected to talk to other\n// coin/token contracts. If you want to create a standards-compliant\n// token, see: https://github.com/ConsenSys/Tokens. Cheers!\n\ncontract MetaCoin {\n\tmapping (address => uint) balances;\n\n\tevent Transfer(address indexed _from, address indexed _to, uint256 _value);\n\n\tfunction MetaCoin() public {\n\t\tbalances[tx.origin] = 10000;\n\t}\n\n\tfunction sendCoin(address receiver, uint amount) public returns(bool sufficient) {\n\t\tif (balances[msg.sender] < amount) return false;\n\t\tbalances[msg.sender] -= amount;\n\t\tbalances[receiver] += amount;\n\t\tTransfer(msg.sender, receiver, amount);\n\t\treturn true;\n\t}\n\n\tfunction getBalanceInEth(address addr) view public returns(uint){\n\t\treturn ConvertLib.convert(getBalance(addr),2);\n\t}\n\n\tfunction getBalance(address addr) view public returns(uint) {\n\t\treturn balances[addr];\n\t}\n}\n", + "sourcePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/MetaCoin.sol", + "ast": { + "attributes": { + "absolutePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/MetaCoin.sol", + "exportedSymbols": { + "MetaCoin": [ + 112 + ] + } + }, + "children": [ + { + "attributes": { + "literals": [ + "solidity", + "^", + "0.4", + ".2" + ] + }, + "id": 18, + "name": "PragmaDirective", + "src": "0:23:1" + }, + { + "attributes": { + "SourceUnit": 17, + "absolutePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/ConvertLib.sol", + "file": "./ConvertLib.sol", + "scope": 113, + "symbolAliases": [ + null + ], + "unitAlias": "" + }, + "id": 19, + "name": "ImportDirective", + "src": "25:26:1" + }, + { + "attributes": { + "baseContracts": [ + null + ], + "contractDependencies": [ + null + ], + "contractKind": "contract", + "documentation": null, + "fullyImplemented": true, + "linearizedBaseContracts": [ + 112 + ], + "name": "MetaCoin", + "scope": 113 + }, + "children": [ + { + "attributes": { + "constant": false, + "name": "balances", + "scope": 112, + "stateVariable": true, + "storageLocation": "default", + "type": "mapping(address => uint256)", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "type": "mapping(address => uint256)" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 20, + "name": "ElementaryTypeName", + "src": "345:7:1" + }, + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 21, + "name": "ElementaryTypeName", + "src": "356:4:1" + } + ], + "id": 22, + "name": "Mapping", + "src": "336:25:1" + } + ], + "id": 23, + "name": "VariableDeclaration", + "src": "336:34:1" + }, + { + "attributes": { + "anonymous": false, + "name": "Transfer" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "indexed": true, + "name": "_from", + "scope": 31, + "stateVariable": false, + "storageLocation": "default", + "type": "address", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 24, + "name": "ElementaryTypeName", + "src": "389:7:1" + } + ], + "id": 25, + "name": "VariableDeclaration", + "src": "389:21:1" + }, + { + "attributes": { + "constant": false, + "indexed": true, + "name": "_to", + "scope": 31, + "stateVariable": false, + "storageLocation": "default", + "type": "address", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 26, + "name": "ElementaryTypeName", + "src": "412:7:1" + } + ], + "id": 27, + "name": "VariableDeclaration", + "src": "412:19:1" + }, + { + "attributes": { + "constant": false, + "indexed": false, + "name": "_value", + "scope": 31, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint256", + "type": "uint256" + }, + "id": 28, + "name": "ElementaryTypeName", + "src": "433:7:1" + } + ], + "id": 29, + "name": "VariableDeclaration", + "src": "433:14:1" + } + ], + "id": 30, + "name": "ParameterList", + "src": "388:60:1" + } + ], + "id": 31, + "name": "EventDefinition", + "src": "374:75:1" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": true, + "modifiers": [ + null + ], + "name": "MetaCoin", + "payable": false, + "scope": 112, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "attributes": { + "parameters": [ + null + ] + }, + "children": [], + "id": 32, + "name": "ParameterList", + "src": "469:2:1" + }, + { + "attributes": { + "parameters": [ + null + ] + }, + "children": [], + "id": 33, + "name": "ParameterList", + "src": "479:0:1" + }, + { + "children": [ + { + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "=", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": true, + "isPure": false, + "lValueRequested": true, + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 23, + "type": "mapping(address => uint256)", + "value": "balances" + }, + "id": 34, + "name": "Identifier", + "src": "483:8:1" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "member_name": "origin", + "referencedDeclaration": null, + "type": "address" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 191, + "type": "tx", + "value": "tx" + }, + "id": 35, + "name": "Identifier", + "src": "492:2:1" + } + ], + "id": 36, + "name": "MemberAccess", + "src": "492:9:1" + } + ], + "id": 37, + "name": "IndexAccess", + "src": "483:19:1" + }, + { + "attributes": { + "argumentTypes": null, + "hexvalue": "3130303030", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "subdenomination": null, + "token": "number", + "type": "int_const 10000", + "value": "10000" + }, + "id": 38, + "name": "Literal", + "src": "505:5:1" + } + ], + "id": 39, + "name": "Assignment", + "src": "483:27:1" + } + ], + "id": 40, + "name": "ExpressionStatement", + "src": "483:27:1" + } + ], + "id": 41, + "name": "Block", + "src": "479:35:1" + } + ], + "id": 42, + "name": "FunctionDefinition", + "src": "452:62:1" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "sendCoin", + "payable": false, + "scope": 112, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "receiver", + "scope": 83, + "stateVariable": false, + "storageLocation": "default", + "type": "address", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 43, + "name": "ElementaryTypeName", + "src": "535:7:1" + } + ], + "id": 44, + "name": "VariableDeclaration", + "src": "535:16:1" + }, + { + "attributes": { + "constant": false, + "name": "amount", + "scope": 83, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 45, + "name": "ElementaryTypeName", + "src": "553:4:1" + } + ], + "id": 46, + "name": "VariableDeclaration", + "src": "553:11:1" + } + ], + "id": 47, + "name": "ParameterList", + "src": "534:31:1" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "sufficient", + "scope": 83, + "stateVariable": false, + "storageLocation": "default", + "type": "bool", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "bool", + "type": "bool" + }, + "id": 48, + "name": "ElementaryTypeName", + "src": "581:4:1" + } + ], + "id": 49, + "name": "VariableDeclaration", + "src": "581:15:1" + } + ], + "id": 50, + "name": "ParameterList", + "src": "580:17:1" + }, + { + "children": [ + { + "attributes": { + "falseBody": null + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "<", + "type": "bool" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": true, + "isPure": false, + "lValueRequested": false, + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 23, + "type": "mapping(address => uint256)", + "value": "balances" + }, + "id": 51, + "name": "Identifier", + "src": "606:8:1" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "member_name": "sender", + "referencedDeclaration": null, + "type": "address" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 181, + "type": "msg", + "value": "msg" + }, + "id": 52, + "name": "Identifier", + "src": "615:3:1" + } + ], + "id": 53, + "name": "MemberAccess", + "src": "615:10:1" + } + ], + "id": 54, + "name": "IndexAccess", + "src": "606:20:1" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 46, + "type": "uint256", + "value": "amount" + }, + "id": 55, + "name": "Identifier", + "src": "629:6:1" + } + ], + "id": 56, + "name": "BinaryOperation", + "src": "606:29:1" + }, + { + "attributes": { + "functionReturnParameters": 50 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "hexvalue": "66616c7365", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "subdenomination": null, + "token": "bool", + "type": "bool", + "value": "false" + }, + "id": 57, + "name": "Literal", + "src": "644:5:1" + } + ], + "id": 58, + "name": "Return", + "src": "637:12:1" + } + ], + "id": 59, + "name": "IfStatement", + "src": "602:47:1" + }, + { + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "-=", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": true, + "isPure": false, + "lValueRequested": true, + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 23, + "type": "mapping(address => uint256)", + "value": "balances" + }, + "id": 60, + "name": "Identifier", + "src": "653:8:1" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "member_name": "sender", + "referencedDeclaration": null, + "type": "address" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 181, + "type": "msg", + "value": "msg" + }, + "id": 61, + "name": "Identifier", + "src": "662:3:1" + } + ], + "id": 62, + "name": "MemberAccess", + "src": "662:10:1" + } + ], + "id": 63, + "name": "IndexAccess", + "src": "653:20:1" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 46, + "type": "uint256", + "value": "amount" + }, + "id": 64, + "name": "Identifier", + "src": "677:6:1" + } + ], + "id": 65, + "name": "Assignment", + "src": "653:30:1" + } + ], + "id": 66, + "name": "ExpressionStatement", + "src": "653:30:1" + }, + { + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "+=", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": true, + "isPure": false, + "lValueRequested": true, + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 23, + "type": "mapping(address => uint256)", + "value": "balances" + }, + "id": 67, + "name": "Identifier", + "src": "687:8:1" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 44, + "type": "address", + "value": "receiver" + }, + "id": 68, + "name": "Identifier", + "src": "696:8:1" + } + ], + "id": 69, + "name": "IndexAccess", + "src": "687:18:1" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 46, + "type": "uint256", + "value": "amount" + }, + "id": 70, + "name": "Identifier", + "src": "709:6:1" + } + ], + "id": 71, + "name": "Assignment", + "src": "687:28:1" + } + ], + "id": 72, + "name": "ExpressionStatement", + "src": "687:28:1" + }, + { + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "isStructConstructorCall": false, + "lValueRequested": false, + "names": [ + null + ], + "type": "tuple()", + "type_conversion": false + }, + "children": [ + { + "attributes": { + "argumentTypes": [ + { + "typeIdentifier": "t_address", + "typeString": "address" + }, + { + "typeIdentifier": "t_address", + "typeString": "address" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + ], + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 31, + "type": "function (address,address,uint256)", + "value": "Transfer" + }, + "id": 73, + "name": "Identifier", + "src": "719:8:1" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "member_name": "sender", + "referencedDeclaration": null, + "type": "address" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 181, + "type": "msg", + "value": "msg" + }, + "id": 74, + "name": "Identifier", + "src": "728:3:1" + } + ], + "id": 75, + "name": "MemberAccess", + "src": "728:10:1" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 44, + "type": "address", + "value": "receiver" + }, + "id": 76, + "name": "Identifier", + "src": "740:8:1" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 46, + "type": "uint256", + "value": "amount" + }, + "id": 77, + "name": "Identifier", + "src": "750:6:1" + } + ], + "id": 78, + "name": "FunctionCall", + "src": "719:38:1" + } + ], + "id": 79, + "name": "ExpressionStatement", + "src": "719:38:1" + }, + { + "attributes": { + "functionReturnParameters": 50 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "hexvalue": "74727565", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "subdenomination": null, + "token": "bool", + "type": "bool", + "value": "true" + }, + "id": 80, + "name": "Literal", + "src": "768:4:1" + } + ], + "id": 81, + "name": "Return", + "src": "761:11:1" + } + ], + "id": 82, + "name": "Block", + "src": "598:178:1" + } + ], + "id": 83, + "name": "FunctionDefinition", + "src": "517:259:1" + }, + { + "attributes": { + "constant": true, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "getBalanceInEth", + "payable": false, + "scope": 112, + "stateMutability": "view", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "addr", + "scope": 99, + "stateVariable": false, + "storageLocation": "default", + "type": "address", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 84, + "name": "ElementaryTypeName", + "src": "804:7:1" + } + ], + "id": 85, + "name": "VariableDeclaration", + "src": "804:12:1" + } + ], + "id": 86, + "name": "ParameterList", + "src": "803:14:1" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "", + "scope": 99, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 87, + "name": "ElementaryTypeName", + "src": "838:4:1" + } + ], + "id": 88, + "name": "VariableDeclaration", + "src": "838:4:1" + } + ], + "id": 89, + "name": "ParameterList", + "src": "837:6:1" + }, + { + "children": [ + { + "attributes": { + "functionReturnParameters": 89 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "isStructConstructorCall": false, + "lValueRequested": false, + "names": [ + null + ], + "type": "uint256", + "type_conversion": false + }, + "children": [ + { + "attributes": { + "argumentTypes": [ + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_rational_2_by_1", + "typeString": "int_const 2" + } + ], + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "member_name": "convert", + "referencedDeclaration": 15, + "type": "function (uint256,uint256) pure returns (uint256)" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 16, + "type": "type(library ConvertLib)", + "value": "ConvertLib" + }, + "id": 90, + "name": "Identifier", + "src": "854:10:1" + } + ], + "id": 91, + "name": "MemberAccess", + "src": "854:18:1" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "isStructConstructorCall": false, + "lValueRequested": false, + "names": [ + null + ], + "type": "uint256", + "type_conversion": false + }, + "children": [ + { + "attributes": { + "argumentTypes": [ + { + "typeIdentifier": "t_address", + "typeString": "address" + } + ], + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 111, + "type": "function (address) view returns (uint256)", + "value": "getBalance" + }, + "id": 92, + "name": "Identifier", + "src": "873:10:1" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 85, + "type": "address", + "value": "addr" + }, + "id": 93, + "name": "Identifier", + "src": "884:4:1" + } + ], + "id": 94, + "name": "FunctionCall", + "src": "873:16:1" + }, + { + "attributes": { + "argumentTypes": null, + "hexvalue": "32", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "subdenomination": null, + "token": "number", + "type": "int_const 2", + "value": "2" + }, + "id": 95, + "name": "Literal", + "src": "890:1:1" + } + ], + "id": 96, + "name": "FunctionCall", + "src": "854:38:1" + } + ], + "id": 97, + "name": "Return", + "src": "847:45:1" + } + ], + "id": 98, + "name": "Block", + "src": "843:53:1" + } + ], + "id": 99, + "name": "FunctionDefinition", + "src": "779:117:1" + }, + { + "attributes": { + "constant": true, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "getBalance", + "payable": false, + "scope": 112, + "stateMutability": "view", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "addr", + "scope": 111, + "stateVariable": false, + "storageLocation": "default", + "type": "address", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 100, + "name": "ElementaryTypeName", + "src": "919:7:1" + } + ], + "id": 101, + "name": "VariableDeclaration", + "src": "919:12:1" + } + ], + "id": 102, + "name": "ParameterList", + "src": "918:14:1" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "", + "scope": 111, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 103, + "name": "ElementaryTypeName", + "src": "953:4:1" + } + ], + "id": 104, + "name": "VariableDeclaration", + "src": "953:4:1" + } + ], + "id": 105, + "name": "ParameterList", + "src": "952:6:1" + }, + { + "children": [ + { + "attributes": { + "functionReturnParameters": 105 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": true, + "isPure": false, + "lValueRequested": false, + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 23, + "type": "mapping(address => uint256)", + "value": "balances" + }, + "id": 106, + "name": "Identifier", + "src": "970:8:1" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 101, + "type": "address", + "value": "addr" + }, + "id": 107, + "name": "Identifier", + "src": "979:4:1" + } + ], + "id": 108, + "name": "IndexAccess", + "src": "970:14:1" + } + ], + "id": 109, + "name": "Return", + "src": "963:21:1" + } + ], + "id": 110, + "name": "Block", + "src": "959:29:1" + } + ], + "id": 111, + "name": "FunctionDefinition", + "src": "899:89:1" + } + ], + "id": 112, + "name": "ContractDefinition", + "src": "315:675:1" + } + ], + "id": 113, + "name": "SourceUnit", + "src": "0:991:1" + }, + "compiler": { + "name": "solc", + "version": "0.4.18+commit.9cf6e910.Emscripten.clang" + }, + "networks": { + "4": { + "events": {}, + "links": { + "ConvertLib": "0x14d00a701a2f0d4d65eebaf191f4f60bbaa1da36" + }, + "address": "0xaea9d31a4aeda9e510f7d85559261c16ea0b6b8b" + }, + "4447": { + "events": {}, + "links": { + "ConvertLib": "0xcfeb869f69431e42cdb54a4f4f105c19c080a601" + }, + "address": "0x254dffcd3277c0b1660f6d42efbb754edababc2b" + } + }, + "schemaVersion": "1.0.1", + "updatedAt": "2017-11-07T20:44:02.307Z" +} \ No newline at end of file diff --git a/console/src/main/java/org/web3j/console/Runner.java b/console/src/main/java/org/web3j/console/Runner.java index 5a3f95119..f52c83bf8 100644 --- a/console/src/main/java/org/web3j/console/Runner.java +++ b/console/src/main/java/org/web3j/console/Runner.java @@ -2,6 +2,7 @@ import org.web3j.codegen.Console; import org.web3j.codegen.SolidityFunctionWrapperGenerator; +import org.web3j.codegen.TruffleJsonFunctionWrapperGenerator; import org.web3j.utils.Version; import static org.web3j.utils.Collection.tail; @@ -36,6 +37,9 @@ public static void main(String[] args) throws Exception { case "solidity": SolidityFunctionWrapperGenerator.run(tail(args)); break; + case "truffle": + TruffleJsonFunctionWrapperGenerator.run(tail(args)); + break; case "version": Console.exitSuccess("Version: " + Version.getVersion() + "\n" + "Build timestamp: " + Version.getTimestamp()); diff --git a/core/src/main/java/org/web3j/protocol/core/methods/response/AbiDefinition.java b/core/src/main/java/org/web3j/protocol/core/methods/response/AbiDefinition.java index ecdab2076..91d7e44c5 100644 --- a/core/src/main/java/org/web3j/protocol/core/methods/response/AbiDefinition.java +++ b/core/src/main/java/org/web3j/protocol/core/methods/response/AbiDefinition.java @@ -16,19 +16,44 @@ public class AbiDefinition { private String type; private boolean payable; + /** + * The stateMutability function modifier. + * <p>this does not factor into the <code>#hashCode()</code> or <code>#equals()</code> logic + * since multiple functions with the same signature that only differ in mutability are not + * allowed in Solidity.</p> + * <p> + * Valid values are: + * <ul> + * <li>pure</li> + * <li>view</li> + * <li>nonpayable</li> + * <li>payable</li> + * </ul> + * </p> + */ + private String stateMutability; + public AbiDefinition() { } public AbiDefinition(boolean constant, List<NamedType> inputs, String name, List<NamedType> outputs, String type, boolean payable) { + this(constant, inputs, name, outputs, type, payable, null); + } + + public AbiDefinition(boolean constant, List<NamedType> inputs, String name, + List<NamedType> outputs, String type, boolean payable, + String stateMutability) { this.constant = constant; this.inputs = inputs; this.name = name; this.outputs = outputs; this.type = type; this.payable = payable; + this.stateMutability = stateMutability; } + public boolean isConstant() { return constant; } @@ -77,6 +102,14 @@ public void setPayable(boolean payable) { this.payable = payable; } + public String getStateMutability() { + return stateMutability; + } + + public void setStateMutability(String stateMutability) { + this.stateMutability = stateMutability; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -106,6 +139,11 @@ public boolean equals(Object o) { ? !getOutputs().equals(that.getOutputs()) : that.getOutputs() != null) { return false; } + if (getStateMutability() != null + ? !getStateMutability().equals(that.getStateMutability()) + : that.getStateMutability() != null) { + return false; + } return getType() != null ? getType().equals(that.getType()) : that.getType() == null; } @@ -118,6 +156,7 @@ public int hashCode() { result = 31 * result + (getOutputs() != null ? getOutputs().hashCode() : 0); result = 31 * result + (getType() != null ? getType().hashCode() : 0); result = 31 * result + (isPayable() ? 1 : 0); + result = 31 * result + (getStateMutability() != null ? getStateMutability().hashCode() : 0); return result; } @@ -172,6 +211,7 @@ public boolean equals(Object o) { if (isIndexed() != namedType.isIndexed()) { return false; } + if (getName() != null ? !getName().equals(namedType.getName()) : namedType.getName() != null) { return false; diff --git a/core/src/main/java/org/web3j/tx/Contract.java b/core/src/main/java/org/web3j/tx/Contract.java index ee9af948d..8f6f4e481 100644 --- a/core/src/main/java/org/web3j/tx/Contract.java +++ b/core/src/main/java/org/web3j/tx/Contract.java @@ -4,7 +4,9 @@ import java.lang.reflect.Constructor; import java.math.BigInteger; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import org.web3j.abi.EventEncoder; @@ -41,6 +43,7 @@ public abstract class Contract extends ManagedTransaction { private final BigInteger gasPrice; private final BigInteger gasLimit; private TransactionReceipt transactionReceipt; + private Map<String, String> deployedAddresses; protected Contract(String contractBinary, String contractAddress, Web3j web3j, TransactionManager transactionManager, @@ -369,4 +372,31 @@ protected List<EventValues> extractEventParameters( return values; } + + /** + * Subclasses should implement this method to return pre-existing addresses for deployed + * contracts. + * + * @param networkId the network id, for example "1" for the main-net, "3" for ropsten, etc. + * @return the deployed address of the contract, if known, and null otherwise. + */ + protected String getStaticDeployedAddress(String networkId) { + return null; + } + + public final void setDeployedAddress(String networkId, String address) { + if (deployedAddresses == null) { + deployedAddresses = new HashMap<>(); + } + deployedAddresses.put(networkId, address); + } + + public final String getDeployedAddress(String networkId) { + String addr = null; + if (deployedAddresses != null) { + addr = deployedAddresses.get(networkId); + } + return addr == null ? getStaticDeployedAddress(networkId) : addr; + } + } diff --git a/utils/src/main/java/org/web3j/utils/Strings.java b/utils/src/main/java/org/web3j/utils/Strings.java index 37a1ada2c..7d4376e4d 100644 --- a/utils/src/main/java/org/web3j/utils/Strings.java +++ b/utils/src/main/java/org/web3j/utils/Strings.java @@ -47,4 +47,8 @@ public static String zeros(int n) { public static String repeat(char value, int n) { return new String(new char[n]).replace("\0", String.valueOf(value)); } + + public static boolean isEmpty(String s) { + return s == null || s.length() == 0; + } }