├── .github └── FUNDING.yml ├── .gitignore ├── README.md ├── abi ├── basicInfoGetter.abi ├── basicInfoGetter.bin └── problem.txt ├── abiWrapper └── com │ └── micronautics │ └── solidity │ └── BasicInfoGetter.java ├── assembly.sbt ├── bin ├── attachHttp ├── attachIpc ├── demo ├── gethApis ├── isGethListening ├── isWeb3jReady ├── runGeth ├── tweetNewVersion └── web3j ├── build.sbt ├── core-4.5.16.pom ├── demo ├── Demo.scala ├── DemoObservables.scala ├── DemoSmartContracts.scala ├── DemoTransaction.scala └── Main.scala ├── geth.md ├── logos ├── repository-open-graph-template.png ├── repository-open-graph.ai ├── repository-open-graph.png └── web3j-orange.png ├── project ├── build.properties ├── build.sbt ├── ghpages.sbt └── plugins.sbt ├── publish.sbt └── src ├── main ├── resources │ └── logback.xml └── scala │ └── com │ └── micronautics │ └── web3j │ ├── Cmd.scala │ ├── Ether.scala │ ├── EthereumASynchronous.scala │ ├── EthereumSynchronous.scala │ ├── InfuraNetwork.java │ ├── ValueClasses.scala │ ├── Web3JScala.scala │ └── package.scala └── test ├── resources └── basic_info_getter.sol └── scala └── EtherTest.scala /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | [mslinn] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | *.sublime-* 3 | *~ 4 | .cache 5 | .ethereum/ 6 | .github/ 7 | .idea/ 8 | .idea_modules/ 9 | .project 10 | .history 11 | .settings/ 12 | *.iml 13 | *.stackdump 14 | *.zip 15 | #abi/ 16 | #abiWrapper/ 17 | logs/ 18 | project/target/ 19 | target/ 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEATH NOTICE 2 | May 8, 2020: I have abandoned this project and will not update it. If someone else wants to take it over please contact me. 3 | 4 | -- Mike 5 | 6 | # Web3J-Scala Library 7 | 8 | 9 | 10 | [![GitHub version](https://badge.fury.io/gh/mslinn%2Fweb3j-scala.svg)](https://badge.fury.io/gh/mslinn%2Fweb3j-scala) 11 | 12 | `web3j-scala` is an idiomatic Scala wrapper around [Web3J](https://www.web3j.io) for Ethereum. 13 | Web3J is a lightweight, reactive, somewhat type safe Java and Android library for integrating with nodes on Ethereum blockchains. 14 | 15 | Web3J features RxJava extensions, and `web3j-scala` wraps that syntax in Scala goodness. 16 | For example, the `web3j-scala` [observable methods](http://mslinn.github.io/web3j-scala/latest/api/com/micronautics/web3j/Web3JScala$.html) 17 | provide [simple and efficient application code](https://github.com/mslinn/web3j-scala/blob/master/demo/DemoObservables.scala#L14-L22). 18 | Scala's [value classes are used](https://github.com/mslinn/web3j-scala/blob/master/src/main/scala/com/micronautics/web3j/ValueClasses.scala) 19 | to provide much stronger type safety than Web3J, without incurring a runtime penalty. 20 | 21 | ## Use As a Library 22 | Add this to your SBT project's `build.sbt`: 23 | 24 | resolvers ++= Seq( 25 | "micronautics/scala on bintray" at "https://dl.bintray.com/micronautics/scala", 26 | "ethereum" at "https://dl.bintray.com/ethereum/maven/" 27 | ) 28 | 29 | libraryDependencies += "com.micronautics" %% "web3j-scala" % "4.5.17" withSources() 30 | 31 | This library is cross-built for Scala 2.12 and 2.13. Tested with Oracle JDK 8 and OpenJDK 8 & 11. 32 | 33 | ## Questions and Problems 34 | This library merely wraps [Web3J](https://www.web3j.io), so if you have questions about how to use this library, 35 | please [read their docs](https://web3j.readthedocs.io/en/stable/quickstart.html), and participate in [their Gitter channel](https://gitter.im/web3j/web3j). 36 | 37 | If you find a bug in this library you can [post an issue here](https://github.com/mslinn/web3j-scala/issues). 38 | 39 | ## Run the Demo Program 40 | The demo program performs the following: 41 | - Follows the outline of the [Web3J Getting Started](https://docs.web3j.io/getting_started.html#start-sending-requests) documentation, 42 | adapted for Web3J-Scala, including synchronous and asynchronous versions of the available methods. 43 | - Compiles an example Solidity program that defines a smart contract. 44 | - Creates a JVM wrapper from an example smart contract. 45 | 46 | To run the demo: 47 | 1. Start up an Ethereum client if you don’t already have one running, such as `geth`. 48 | The `bin/runGeth` script invokes `geth` with the following options, which are convenient for development but not secure enough for production: 49 | - The Ethereum data directory is set to `~/.ethereum`, or a subdirectory that depends on the network chosen; 50 | the directory will be created if required. 51 | - HTTP-RPC server at `localhost:8545` is enabled, and all APIs are allowed. 52 | - Ethereum's experimental Whisper message facility is enabled. 53 | - Inter-process communication will be via a virtual file called `geth.ipc`, 54 | located at `~/.ethereum` or a subdirectory. 55 | - WS-RPC server at `localhost:8546` is enabled, and all APIs are allowed. 56 | - Info verbosity is specified. 57 | - A log file for the `geth` output will be written, or overwritten, in `logs/geth.log`; 58 | the `log/` directory will be created if it does not already exist. 59 | ``` 60 | $ mkdir logs/ 61 | $ geth \ 62 | #--datadir .ethereum/devnet --dev \ # boots quickly but has no deployed contracts from others 63 | --datadir .ethereum/rinkeby --rinkeby \ # takes about 15 minutes to boot, but has contracts 64 | --ipcpath geth.ipc \ 65 | --metrics \ 66 | --rpc \ 67 | --rpcapi eth,net,web3,clique,debug,eth,miner,personal,rpc,ssh,txpool \ 68 | --shh \ 69 | --ws \ 70 | --wsapi eth,net,web3,clique,debug,eth,miner,personal,rpc,ssh,txpool \ 71 | --verbosity 2 72 | ``` 73 | You will see the message `No etherbase set and no accounts found as default`. 74 | Etherbase is the index into `personal.listAccounts` which determines the account to send Ether too. 75 | You can specify this value with the option `--etherbase 0`. 76 | 2. The shell that you just used will continuously scroll output so long as `geth` continues to run, 77 | so type the following into another shell: 78 | ``` 79 | $ bin/demo 80 | ``` 81 | The demo has two major components: 82 | 1. [Creates a JVM wrapper](https://github.com/mslinn/web3j-scala/blob/master/demo/DemoSmartContracts.scala) 83 | for the [sample smart contract](https://github.com/mslinn/web3j-scala/blob/master/src/test/resources/basic_info_getter.sol). 84 | 2. The second portion of the demo consists of the following: 85 | - Examples of using `web3j-scala`'s [synchrounous and asynchronous APIs](https://github.com/mslinn/web3j-scala/blob/master/demo/Demo.scala) 86 | - Examples of working with [RxJava's Observables from Scala](https://github.com/mslinn/web3j-scala/blob/master/demo/DemoObservables.scala) 87 | - Examples of working with [JVM wrappers around Ethereum smart contracts](https://github.com/mslinn/web3j-scala/blob/master/demo/DemoSmartContracts.scala). 88 | - Examples of using [transactions](https://github.com/mslinn/web3j-scala/blob/master/demo/DemoTransaction.scala) 89 | with Ethereum wallet files and the Ethereum client. 90 | 3. The `bin/web3j` script runs the [Web3J command-line console](https://docs.web3j.io/command_line.html). 91 | The script builds a fat jar the first time it is run, so the command runs quickly on subsequent invocations. 92 | 4. More scripts are provided in the `bin/` directory, including: 93 | - [bin/attachHttp](https://github.com/mslinn/web3j-scala/blob/master/bin/attachHttp) - 94 | Attach to a running geth instance via HTTP and open a 95 | [JavaScript console](https://godoc.org/github.com/robertkrimen/otto) 96 | - [bin/attachIpc](https://github.com/mslinn/web3j-scala/blob/master/bin/attachIpc) - 97 | Attach to a running geth instance via IPC and open a JavaScript console. 98 | This script might need to be edited if a network other than `devnet` is used. 99 | - [bin/getApis](https://github.com/mslinn/web3j-scala/blob/master/bin/gethApis) - 100 | Reports the available APIs exposed by this `geth` instance. 101 | - [bin/isGethListening](https://github.com/mslinn/web3j-scala/blob/master/bin/isGethListening) - 102 | Verifies that `geth` is listening on HTTP port 8545 103 | 104 | ## Developers 105 | ### API Documentation 106 | * [This library's Scaladoc is here](http://mslinn.github.io/web3j-scala/latest/api/com/micronautics/web3j/index.html) 107 | and the [gitter channel is here](https://gitter.im/web3j-scala/Lobby). 108 | 109 | * [The Web3J JavaDoc is here](https://jar-download.com/java-documentation-javadoc.php?a=core&g=org.web3j&v=3.0.2), 110 | and here is the [Web3J gitter channel](https://gitter.im/web3j/web3j). 111 | 112 | ### Publishing 113 | 1. Update the version string in `build.sbt` and in this `README.md` before attempting to publish to Bintray. 114 | 2. Commit changes with a descriptive comment: 115 | ``` 116 | $ git add -a && git commit -m "Comment here" 117 | ``` 118 | 3. Publish a new version of this library, including committing changes and updating the Scaladoc with this command: 119 | ``` 120 | $ sbt publishAndTag 121 | ``` 122 | 123 | ### Updating Scaladoc 124 | 1. Use the Scaladoc project; first do a [preflight check of the Scaladoc output](https://github.com/mslinn/multi-scaladoc#preflight-check-optimize-your-scaladoc-source): 125 | ``` 126 | sbt "; project web3j-scala; doc; project demo; doc" 127 | ``` 128 | 129 | 2. Now [Update the Git Version String and Make a New Tag](https://github.com/mslinn/multi-scaladoc#update-the-git-version-string-and-make-a-new-tag). 130 | 131 | 3. Now [edit the multi-scaladoc settings](https://github.com/mslinn/multi-scaladoc#running-this-program) 132 | ``` 133 | export SCALADOC_SUB_PROJECT_NAMES="web3j-scala,demo" 134 | ``` 135 | 136 | 4. Run multi-scaladoc: 137 | ``` 138 | ../scaladoc/bin/run 139 | ``` 140 | 141 | ### Updating Scaladoc and Committing Changes Without Publishing a New Version 142 | This task rebuilds the docs, commits the git repository, and publishes the updated Scaladoc without publishing a new version: 143 | 144 | $ sbt commitAndDoc 145 | 146 | ## Sponsor 147 | 148 | 149 | This project is sponsored by [Micronautics Research Corporation](http://www.micronauticsresearch.com/), 150 | the company that delivers online Scala training via [ScalaCourses.com](http://www.ScalaCourses.com). 151 | You can learn Scala by taking the [Introduction to Scala](http://www.ScalaCourses.com/showCourse/40), 152 | and [Intermediate Scala](http://www.ScalaCourses.com/showCourse/45) courses. 153 | 154 | Please [contact us](mailto:sales@micronauticsresearch.com) to discuss your organization’s training needs. 155 | 156 | ## License 157 | This software is published under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0.html). 158 | -------------------------------------------------------------------------------- /abi/basicInfoGetter.abi: -------------------------------------------------------------------------------- 1 | [{"constant":true,"inputs":[],"name":"getContractAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getContractBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentBlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTxGasprice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBlockTimestamp","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMsgSender","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentGaslimit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMsgGas","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentDifficulty","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"getMsgValue","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"getTxOrigin","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getMsgData","outputs":[{"name":"","type":"bytes"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentMinerAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}] -------------------------------------------------------------------------------- /abi/basicInfoGetter.bin: -------------------------------------------------------------------------------- 1 | 6060604052341561000f57600080fd5b60008054600160a060020a033316600160a060020a031990911617905561038f8061003b6000396000f3006060604052600436106100cf5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166332a2c5d081146100d457806341c0e1b5146101105780636f9fb98a146101255780636fd902e11461014a57806377e5bf841461015d578063796b89b9146101705780637a6ce2e11461018357806392b7d5b9146101965780639d5c6061146101a9578063a1188e56146101bc578063a17042cc146101cf578063b8077e28146101d7578063c8e7ca2e146101ea578063f8f46b5f14610274575b600080fd5b34156100df57600080fd5b6100e7610287565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b341561011b57600080fd5b61012361028b565b005b341561013057600080fd5b6101386102cc565b60405190815260200160405180910390f35b341561015557600080fd5b6101386102e7565b341561016857600080fd5b6101386102eb565b341561017b57600080fd5b6101386102ef565b341561018e57600080fd5b6100e76102f3565b34156101a157600080fd5b6101386102f7565b34156101b457600080fd5b6101386102fb565b34156101c757600080fd5b610138610303565b610138610307565b34156101e257600080fd5b6100e761030b565b34156101f557600080fd5b6101fd61030f565b60405160208082528190810183818151815260200191508051906020019080838360005b83811015610239578082015183820152602001610221565b50505050905090810190601f1680156102665780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561027f57600080fd5b6100e761034d565b3090565b6000543373ffffffffffffffffffffffffffffffffffffffff908116911614156102ca5760005473ffffffffffffffffffffffffffffffffffffffff16ff5b565b73ffffffffffffffffffffffffffffffffffffffff30163190565b4390565b3a90565b4290565b3390565b4590565b60005a905090565b4490565b3490565b3290565b610317610351565b6000368080601f016020809104026020016040519081016040528181529291906020840183838082843750949550505050505090565b4190565b602060405190810160405260008152905600a165627a7a7230582013a79aa2701d45e426efdad37282ae3be07edda51eed0dbac13611b8053a3fc80029 -------------------------------------------------------------------------------- /abi/problem.txt: -------------------------------------------------------------------------------- 1 | I am having a problem generating a wrapper from a Solidity 0.4.18 program. 2 | ``` 3 | $ solc --bin --abi --optimize --overwrite -o abi/ src/test/resources/basic_info_getter.sol 4 | 5 | $ l abi 6 | total 16 7 | drwxrwxr-x 2 mslinn mslinn 4096 Nov 10 12:33 ./ 8 | drwxrwxr-x 12 mslinn mslinn 4096 Nov 10 12:33 ../ 9 | -rw-rw-r-- 1 mslinn mslinn 2227 Nov 10 12:33 basicInfoGetter.abi 10 | -rw-rw-r-- 1 mslinn mslinn 1940 Nov 10 12:33 basicInfoGetter.bin 11 | 12 | $ bin/web3j solidity generate abi/basicInfoGetter.bin abi/basicInfoGetter.abi -o abiWrapper/ -p com.micronautics.solidity 13 | 14 | _ _____ _ _ 15 | | | |____ (_) (_) 16 | __ _____| |__ / /_ _ ___ 17 | \ \ /\ / / _ \ '_ \ \ \ | | | / _ \ 18 | \ V V / __/ |_) |.___/ / | _ | || (_) | 19 | \_/\_/ \___|_.__/ \____/| |(_)|_| \___/ 20 | _/ | 21 | |__/ 22 | 23 | Invalid input binary file specified: abi/basic_info_getter.bin 24 | ``` 25 | 26 | I have copied the .sol, .abi and .bin files to https://www.micronauticsresearch.com/abi.zip 27 | Suggestions? 28 | -------------------------------------------------------------------------------- /abiWrapper/com/micronautics/solidity/BasicInfoGetter.java: -------------------------------------------------------------------------------- 1 | package com.micronautics.solidity; 2 | 3 | import java.math.BigInteger; 4 | import java.util.Collections; 5 | import org.web3j.abi.TypeReference; 6 | import org.web3j.abi.datatypes.Address; 7 | import org.web3j.abi.datatypes.DynamicBytes; 8 | import org.web3j.abi.datatypes.Function; 9 | import org.web3j.abi.datatypes.generated.Uint256; 10 | import org.web3j.crypto.Credentials; 11 | import org.web3j.protocol.Web3j; 12 | import org.web3j.protocol.core.RemoteCall; 13 | import org.web3j.protocol.core.methods.response.TransactionReceipt; 14 | import org.web3j.tx.Contract; 15 | import org.web3j.tx.TransactionManager; 16 | import org.web3j.tx.gas.StaticGasProvider; 17 | 18 | /** 19 | *

Auto generated code. 20 | *

Do not modify! 21 | *

Please use the web3j command line tools, 22 | * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the 23 | * codegen module to update. 24 | * 25 | *

Generated with web3j version 3.0.2. 26 | */ 27 | public final class BasicInfoGetter extends Contract { 28 | private static final String BINARY = "6060604052341561000f57600080fd5b60008054600160a060020a033316600160a060020a031990911617905561038f8061003b6000396000f3006060604052600436106100cf5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166332a2c5d081146100d457806341c0e1b5146101105780636f9fb98a146101255780636fd902e11461014a57806377e5bf841461015d578063796b89b9146101705780637a6ce2e11461018357806392b7d5b9146101965780639d5c6061146101a9578063a1188e56146101bc578063a17042cc146101cf578063b8077e28146101d7578063c8e7ca2e146101ea578063f8f46b5f14610274575b600080fd5b34156100df57600080fd5b6100e7610287565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b341561011b57600080fd5b61012361028b565b005b341561013057600080fd5b6101386102cc565b60405190815260200160405180910390f35b341561015557600080fd5b6101386102e7565b341561016857600080fd5b6101386102eb565b341561017b57600080fd5b6101386102ef565b341561018e57600080fd5b6100e76102f3565b34156101a157600080fd5b6101386102f7565b34156101b457600080fd5b6101386102fb565b34156101c757600080fd5b610138610303565b610138610307565b34156101e257600080fd5b6100e761030b565b34156101f557600080fd5b6101fd61030f565b60405160208082528190810183818151815260200191508051906020019080838360005b83811015610239578082015183820152602001610221565b50505050905090810190601f1680156102665780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561027f57600080fd5b6100e761034d565b3090565b6000543373ffffffffffffffffffffffffffffffffffffffff908116911614156102ca5760005473ffffffffffffffffffffffffffffffffffffffff16ff5b565b73ffffffffffffffffffffffffffffffffffffffff30163190565b4390565b3a90565b4290565b3390565b4590565b60005a905090565b4490565b3490565b3290565b610317610351565b6000368080601f016020809104026020016040519081016040528181529291906020840183838082843750949550505050505090565b4190565b602060405190810160405260008152905600a165627a7a7230582013a79aa2701d45e426efdad37282ae3be07edda51eed0dbac13611b8053a3fc80029"; 29 | 30 | private BasicInfoGetter(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { 31 | super(BINARY, contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit)); 32 | } 33 | 34 | private BasicInfoGetter(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { 35 | super(BINARY, contractAddress, web3j, transactionManager, new StaticGasProvider(gasPrice, gasLimit)); 36 | } 37 | 38 | /*public RemoteCall getContractAddress() { 39 | Function function = new Function("getContractAddress", 40 | Arrays.asList(), 41 | Arrays.>asList(new TypeReference

() {})); 42 | return executeRemoteCallSingleValueReturn(function, String.class); 43 | }*/ 44 | 45 | public RemoteCall kill() { 46 | Function function = new Function( 47 | "kill", 48 | Collections.emptyList(), 49 | Collections.emptyList()); 50 | return executeRemoteCallTransaction(function); 51 | } 52 | 53 | public RemoteCall getContractBalance() { 54 | Function function = new Function("getContractBalance", 55 | Collections.emptyList(), 56 | Collections.singletonList(new TypeReference() { 57 | })); 58 | return executeRemoteCallSingleValueReturn(function, BigInteger.class); 59 | } 60 | 61 | public RemoteCall getCurrentBlockNumber() { 62 | Function function = new Function("getCurrentBlockNumber", 63 | Collections.emptyList(), 64 | Collections.singletonList(new TypeReference() {})); 65 | return executeRemoteCallSingleValueReturn(function, BigInteger.class); 66 | } 67 | 68 | public RemoteCall getTxGasprice() { 69 | Function function = new Function("getTxGasprice", 70 | Collections.emptyList(), 71 | Collections.singletonList(new TypeReference() { 72 | })); 73 | return executeRemoteCallSingleValueReturn(function, BigInteger.class); 74 | } 75 | 76 | public RemoteCall getBlockTimestamp() { 77 | Function function = new Function("getBlockTimestamp", 78 | Collections.emptyList(), 79 | Collections.singletonList(new TypeReference() { 80 | })); 81 | return executeRemoteCallSingleValueReturn(function, BigInteger.class); 82 | } 83 | 84 | public RemoteCall getMsgSender() { 85 | Function function = new Function("getMsgSender", 86 | Collections.emptyList(), 87 | Collections.singletonList(new TypeReference
() {})); 88 | return executeRemoteCallSingleValueReturn(function, String.class); 89 | } 90 | 91 | public RemoteCall getCurrentGaslimit() { 92 | Function function = new Function("getCurrentGaslimit", 93 | Collections.emptyList(), 94 | Collections.singletonList(new TypeReference() {})); 95 | return executeRemoteCallSingleValueReturn(function, BigInteger.class); 96 | } 97 | 98 | public RemoteCall getMsgGas() { 99 | Function function = new Function("getMsgGas", 100 | Collections.emptyList(), 101 | Collections.singletonList(new TypeReference() {})); 102 | return executeRemoteCallSingleValueReturn(function, BigInteger.class); 103 | } 104 | 105 | public RemoteCall getCurrentDifficulty() { 106 | Function function = new Function("getCurrentDifficulty", 107 | Collections.emptyList(), 108 | Collections.singletonList(new TypeReference() {})); 109 | return executeRemoteCallSingleValueReturn(function, BigInteger.class); 110 | } 111 | 112 | public RemoteCall getMsgValue(BigInteger weiValue) { 113 | Function function = new Function( 114 | "getMsgValue", 115 | Collections.emptyList(), 116 | Collections.emptyList()); 117 | return executeRemoteCallTransaction(function, weiValue); 118 | } 119 | 120 | public RemoteCall getTxOrigin() { 121 | Function function = new Function("getTxOrigin", 122 | Collections.emptyList(), 123 | Collections.singletonList(new TypeReference
() {})); 124 | return executeRemoteCallSingleValueReturn(function, String.class); 125 | } 126 | 127 | public RemoteCall getMsgData() { 128 | Function function = new Function("getMsgData", 129 | Collections.emptyList(), 130 | Collections.singletonList(new TypeReference() {})); 131 | return executeRemoteCallSingleValueReturn(function, byte[].class); 132 | } 133 | 134 | public RemoteCall getCurrentMinerAddress() { 135 | Function function = new Function("getCurrentMinerAddress", 136 | Collections.emptyList(), 137 | Collections.singletonList(new TypeReference
() {})); 138 | return executeRemoteCallSingleValueReturn(function, String.class); 139 | } 140 | 141 | public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { 142 | return deployRemoteCall(BasicInfoGetter.class, web3j, credentials, gasPrice, gasLimit, BINARY, ""); 143 | } 144 | 145 | public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { 146 | return deployRemoteCall(BasicInfoGetter.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, ""); 147 | } 148 | 149 | public static BasicInfoGetter load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { 150 | return new BasicInfoGetter(contractAddress, web3j, credentials, gasPrice, gasLimit); 151 | } 152 | 153 | public static BasicInfoGetter load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { 154 | return new BasicInfoGetter(contractAddress, web3j, transactionManager, gasPrice, gasLimit); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /assembly.sbt: -------------------------------------------------------------------------------- 1 | // Settings for sbt assembly 2 | 3 | test in assembly := {} 4 | 5 | mainClass in assembly := Some("org.web3j.console.Runner") 6 | 7 | assemblyMergeStrategy in assembly := { 8 | case PathList("META-INF", xs @ _*) => MergeStrategy.discard 9 | case x => MergeStrategy.first 10 | } 11 | 12 | //fullClasspath in assembly := (fullClasspath in Compile).value 13 | 14 | //exportJars := true 15 | -------------------------------------------------------------------------------- /bin/attachHttp: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Attach to a running geth instance and open a JavaScript console 4 | 5 | geth attach http://localhost:8545 6 | 7 | # Welcome to the Geth JavaScript console! 8 | # 9 | # instance: Geth/v1.7.3-unstable-3ee86a57/linux-amd64/go1.9.1 10 | # coinbase: 0x549d692ea074df8a9585b16775117e732a17f444 11 | # at block: 0 (Wed, 31 Dec 1969 16:00:00 PST) 12 | # modules: clique:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 13 | -------------------------------------------------------------------------------- /bin/attachIpc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Attach to a running geth (dev) instance via IPC: 4 | 5 | geth attach ipc:"${HOME}/.ethereum/devnet/geth.ipc" 6 | 7 | # Welcome to the Geth JavaScript console! 8 | # 9 | # instance: Geth/v1.7.3-unstable-3ee86a57/linux-amd64/go1.9.1 10 | # coinbase: 0x549d692ea074df8a9585b16775117e732a17f444 11 | # at block: 0 (Wed, 31 Dec 1969 16:00:00 PST) 12 | # datadir: /home/mslinn/.ethereum/devnet 13 | # modules: admin:1.0 clique:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0 14 | -------------------------------------------------------------------------------- /bin/demo: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sbt "test:runMain demo.CreateSmartContracts" \ 4 | "test:runMain demo.Main" 5 | -------------------------------------------------------------------------------- /bin/gethApis: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Discover the geth APIs provided by invoking the modules JSON-RPC method 4 | # See https://github.com/ethereum/go-ethereum/wiki/Management-APIs 5 | 6 | network="${1:-devnet}" 7 | 8 | echo '{"jsonrpc":"2.0","method":"rpc_modules","params":[],"id":1}' | \ 9 | nc -NU ${HOME}/.ethereum/${network}/geth.ipc | \ 10 | python -m json.tool 11 | 12 | # Typical response: 13 | # { 14 | # "jsonrpc":"2.0", 15 | # "id":1, 16 | # "result":{ 17 | # "admin":"1.0", 18 | # "clique":"1.0", 19 | # "debug":"1.0", 20 | # "eth":"1.0", 21 | # "miner":"1.0", 22 | # "net":"1.0", 23 | # "personal":"1.0", 24 | # "rpc":"1.0", 25 | # "shh":"1.0", 26 | # "txpool":"1.0", 27 | # "web3":"1.0" 28 | # } 29 | # } 30 | -------------------------------------------------------------------------------- /bin/isGethListening: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Verify that geth is listening on port 8545 4 | 5 | sudo netstat -pan | grep 8545 6 | 7 | # tcp 0 0 127.0.0.1:8545 0.0.0.0:* LISTEN 22296/geth 8 | -------------------------------------------------------------------------------- /bin/isWeb3jReady: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VERSION="$( cat build.sbt | grep 'val web3jVersion =' | cut -d' ' -f 4 | tr -d '"' | tr -d "\r" )" 4 | wget --no-hsts https://repo1.maven.org/maven2/org/web3j/core/$VERSION/core-$VERSION.pom > /dev/null 2>&1 5 | if [ $? -eq 0 ]; then 6 | echo "Web3j v$VERSION is ready!!!" 7 | else 8 | echo "Web3j v$VERSION is NOT ready. Try again later." 9 | fi 10 | 11 | -------------------------------------------------------------------------------- /bin/runGeth: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ETHEREUM_HOME="${HOME}/.ethereum" 4 | 5 | function help { 6 | echo " 7 | Usage: $0 [Network [Options]] 8 | Network defaults to dev. Other supported values are: main, rinkeby and ropsten. 9 | Options can be any geth command-line options that do not conflict or duplicate existing options used. 10 | 11 | This script invokes geth with the following options: 12 | - The Ethereum data directory is set to $ETHEREUM_HOME, or a subdirectory that depends on the network chosen; the directory will be created if required. 13 | - HTTP-RPC server at localhost:8545 is enabled, and all APIs are allowed. 14 | - Ethereum's experimental Whisper message facility is enabled. 15 | - Inter-process communication will be via a virtual file located at $ETHEREUM_HOME/geth.ipc. 16 | - WS-RPC server at localhost:8546 is enabled, and all APIs are allowed. 17 | - Info verbosity is specified. 18 | - A log file for the geth output will be written, or overwritten, in logs/geth.log; 19 | the log/ directory will be created if it does not already exist. 20 | 21 | You will see the message 'No etherbase set and no accounts found as default'. 22 | Etherbase is the index into personal.listAccounts which determines the account to send Ether too. 23 | You can specify this value with this option: --etherbase 0 24 | 25 | geth -h # displays the geth help message; the help message for geth v1.7.3 is available in geth.md. 26 | " 27 | exit 1 28 | } 29 | 30 | if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then help; fi 31 | 32 | case "$1" in 33 | kovan) 34 | echo "Error: The Kovan test network is only supported by Parity" 35 | exit 1 36 | ;; 37 | 38 | main) # Live network, takes hours to boot, real money is at risk with this choice 39 | ETHEREUM_NETWORK=mainnet 40 | ETHEREUM_HOME="$ETHEREUM_HOME" 41 | DATADIR="--datadir $ETHEREUM_HOME" 42 | shift 43 | ;; 44 | 45 | rinkeby) # This test network takes about 15 minutes to boot, and has contracts. Only supported by geth 46 | ETHEREUM_NETWORK=$1 47 | ETHEREUM_HOME="$ETHEREUM_HOME/$ETHEREUM_NETWORK" 48 | DATADIR="--datadir $ETHEREUM_HOME --$ETHEREUM_NETWORK" 49 | shift 50 | ;; 51 | 52 | ropsten) # This test network takes about 15 minutes to boot, and has contracts. Supported by geth and Parity. 53 | ETHEREUM_NETWORK=$1 54 | ETHEREUM_HOME="$ETHEREUM_HOME/$ETHEREUM_NETWORK" 55 | DATADIR="--datadir $ETHEREUM_HOME --testnet" 56 | shift 57 | ;; 58 | 59 | dev) # Generic development network; boots very quickly but has no deployed contracts from others 60 | shift 61 | ETHEREUM_NETWORK=devnet 62 | ETHEREUM_HOME="$ETHEREUM_HOME/$ETHEREUM_NETWORK" 63 | DATADIR="--datadir $ETHEREUM_HOME --dev" 64 | ;; 65 | 66 | "") # Generic development network; boots very quickly but has no deployed contracts from others 67 | ETHEREUM_NETWORK=devnet 68 | ETHEREUM_HOME="$ETHEREUM_HOME/$ETHEREUM_NETWORK" 69 | DATADIR="--datadir $ETHEREUM_HOME --dev" 70 | ;; 71 | esac 72 | 73 | echo "Using $ETHEREUM_NETWORK Ethereum network with home $ETHEREUM_HOME at timestamp $(date)" 74 | 75 | mkdir -p "$ETHEREUM_HOME" 76 | mkdir -p logs/ 77 | 78 | # All geth options are defined here: https://github.com/ethereum/go-ethereum/blob/master/cmd/utils/flags.go#L105 79 | # Seems --ipcapi is no longer supported. Wonder what that means? 80 | # 81 | # Beside the officially exposed DApp API namespaces (eth, shh, web3), Geth provides the following extra API namespaces: 82 | # admin: Geth node management 83 | # debug: Geth node debugging 84 | # miner: Miner and DAG management 85 | # personal: Account management 86 | # txpool: Transaction pool inspection 87 | 88 | APIS_MIN=eth,net,web3 89 | export APIS="$APIS_MIN,clique,debug,eth,miner,personal,rpc,ssh,txpool" # Edit this if desired 90 | 91 | set -xv 92 | geth \ 93 | ${DATADIR} \ 94 | --ipcpath geth.ipc \ 95 | --metrics \ 96 | --rpc \ 97 | --rpcapi $APIS \ 98 | --shh \ 99 | --ws \ 100 | --wsapi $APIS \ 101 | --verbosity 3 \ 102 | "$*" 2> logs/geth.log 103 | set +xv 104 | -------------------------------------------------------------------------------- /bin/tweetNewVersion: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function findSettingValue { 4 | echo "$( grep "$1 :=" build.sbt | cut -d' ' -f 3 | tr -d \" | tr -d '\n' | tr -d '\r' )" 5 | } 6 | 7 | function findVarValue { 8 | echo "$( grep "$1 =" build.sbt | cut -d' ' -f 4 | tr -d \" | tr -d '\n' | tr -d '\r' )" 9 | } 10 | 11 | VER="$( findVarValue web3jVersion )" 12 | 13 | read -r -d '' TWEET << EndOfMessage 14 | I updated web3j-scala to match upstream (web3j v$VER). 15 | web3j-scala supports Scala 2.12 and 2.13. 16 | 17 | https://github.com/mslinn/web3j-scala 18 | 19 | #web3j #ethereum #Scala 20 | EndOfMessage 21 | 22 | echo "$TWEET" 23 | -------------------------------------------------------------------------------- /bin/web3j: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Sample usage: 4 | # bin/web3j -j 5 | # 6 | # -j option forces rebuild of jar 7 | 8 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/.." 9 | cd "$DIR" || exit 1 10 | 11 | # Scan build.sbt for program name, Scala version and program version 12 | function findValue { 13 | grep "$1 :=" build.sbt | cut -d' ' -f 3 | tr -d \" 14 | } 15 | 16 | SCALA_VERSION() { 17 | V=$( findValue scalaVersion ) 18 | case $V in 19 | 2.10.*) echo 2.10 ;; 20 | 2.11.*) echo 2.11 ;; 21 | 2.12.*) echo 2.12 ;; 22 | 2.13.*) echo 2.13 ;; 23 | 3.0.*) echo 3.0 ;; 24 | 3.1.*) echo 3.1 ;; 25 | *) echo UNKNOWN ;; 26 | esac 27 | } 28 | 29 | NAME="$( findValue name )" 30 | VERSION="$( findValue version )" 31 | JAR=target/scala-$(SCALA_VERSION)/$NAME-assembly-$VERSION.jar 32 | 33 | if [ "$1" == -j ] || [ ! -f "${JAR}" ]; then 34 | echo "Building $JAR" 35 | sbt assembly 36 | 37 | if [ "$1" == -j ]; then shift; fi 38 | fi 39 | 40 | java -cp "$JAR" org.web3j.console.Runner "$@" 41 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | val web3jVersion = "4.5.17" 2 | 3 | cancelable := true 4 | 5 | // Travis can be a PITA 6 | crossScalaVersions := { if (new java.io.File("/home/travis").exists) Seq("2.13.1") else Seq("2.12.10", "2.13.1") } 7 | 8 | fork in Test := true 9 | 10 | // define the statements initially evaluated when entering 'console', 'console-quick', but not 'console-project' 11 | initialCommands in console := """import scala.sys.process._ 12 | |import java.math.BigInteger 13 | |import java.util.concurrent.Future 14 | |import org.web3j.protocol._ 15 | |import org.web3j.protocol.infura._ 16 | |""".stripMargin 17 | 18 | javacOptions ++= Seq( 19 | "-Xlint:deprecation", 20 | "-Xlint:unchecked", 21 | "-source", "1.8", 22 | "-target", "1.8", 23 | "-g:vars" 24 | ) 25 | 26 | libraryDependencies ++= Seq( 27 | "org.scala-lang.modules" %% "scala-collection-compat" % "2.1.3" withSources(), 28 | // See https://docs.web3j.io/modules.html 29 | "org.web3j" % "abi" % web3jVersion withSources(), // Application Binary Interface encoders 30 | "org.web3j" % "codegen" % web3jVersion withSources(), // Code generators 31 | //"org.web3j" % "console" % web3jVersion withSources(), // Command-line tools 32 | "org.web3j" % "core" % web3jVersion withSources(), 33 | // "org.web3j" % "crypto" % web3jVersion withSources(), // For transaction signing and key/wallet management 34 | "org.web3j" % "geth" % web3jVersion withSources(), // Geth-specific JSON-RPC module 35 | "org.web3j" % "infura" % "4.2.0" withSources(), // Infura-specific HTTP header support 36 | "org.web3j" % "parity" % web3jVersion withSources(), // Parity-specific JSON-RPC module 37 | // "org.web3j" % "quorum" % "0.7.0" withSources(), // integration with JP Morgan's Quorum 38 | "org.web3j" % "rlp" % web3jVersion withSources(), // Recursive Length Prefix (RLP) encoders 39 | "org.web3j" % "utils" % web3jVersion withSources(), // Minimal set of utility classes 40 | "org.web3j" % "web3j-maven-plugin" % "0.3.5" withSources(), // Create Java classes from solidity contract files 41 | // 42 | "org.scala-lang.modules" %% "scala-java8-compat" % "0.9.0", 43 | "ch.qos.logback" % "logback-classic" % "1.2.3", 44 | // 45 | "org.scalatest" %% "scalatest" % "3.0.8" % Test withSources(), 46 | "junit" % "junit" % "4.12" % Test 47 | ) 48 | 49 | libraryDependencies ++= { // Newer versions of Java have had the runtime library reduced, so include missing Java dependencies 50 | sys.props("java.version") match { 51 | case jv if jv.startsWith("11") => 52 | javacOptions += "-J--add-modules=java.xml.bind" 53 | Seq( 54 | "javax.xml.bind" % "jaxb-api" % "2.3.1" 55 | ) 56 | 57 | case _ => Nil 58 | }} 59 | 60 | licenses += ("Apache-2.0", url("https://www.apache.org/licenses/LICENSE-2.0.html")) 61 | 62 | logLevel := Level.Warn 63 | 64 | // Only show warnings and errors on the screen for compilations. 65 | // This applies to both test:compile and compile and is Info by default 66 | logLevel in compile := Level.Warn 67 | 68 | // Level.INFO is needed to see detailed output when running tests 69 | logLevel in test := Level.Info 70 | 71 | name := "web3j-scala" 72 | 73 | organization := "com.micronautics" 74 | 75 | resolvers ++= Seq( 76 | "Ethereum Maven" at "https://dl.bintray.com/ethereum/maven/", 77 | "bintray" at "https://bintray.com/web3j/maven/org.web3j", 78 | //"Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots" 79 | ) 80 | 81 | scalacOptions ++= Seq( // From https://tpolecat.github.io/2017/04/25/scalac-flags.html 82 | "-deprecation", // Emit warning and location for usages of deprecated APIs. 83 | "-encoding", "utf-8", // Specify character encoding used by source files. 84 | "-explaintypes", // Explain type errors in more detail. 85 | "-feature", // Emit warning and location for usages of features that should be imported explicitly. 86 | "-language:existentials", // Existential types (besides wildcard types) can be written and inferred 87 | "-language:experimental.macros", // Allow macro definition (besides implementation and application) 88 | "-language:higherKinds", // Allow higher-kinded types 89 | "-language:implicitConversions", // Allow definition of implicit functions called views 90 | "-unchecked", // Enable additional warnings where generated code depends on assumptions. 91 | "-Xcheckinit", // Wrap field accessors to throw an exception on uninitialized access. 92 | "-Xlint:adapted-args", // Warn if an argument list is modified to match the receiver. 93 | "-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error. 94 | "-Xlint:delayedinit-select", // Selecting member of DelayedInit. 95 | "-Xlint:doc-detached", // A Scaladoc comment appears to be detached from its element. 96 | "-Xlint:infer-any", // Warn when a type argument is inferred to be `Any`. 97 | "-Xlint:missing-interpolator", // A string literal appears to be missing an interpolator id. 98 | "-Xlint:nullary-override", // Warn when non-nullary `def f()' overrides nullary `def f'. 99 | "-Xlint:nullary-unit", // Warn when nullary methods return Unit. 100 | "-Xlint:option-implicit", // Option.apply used implicit view. 101 | "-Xlint:package-object-classes", // Class or object defined in package object. 102 | "-Xlint:poly-implicit-overload", // Parameterized overloaded implicit methods are not visible as view bounds. 103 | "-Xlint:private-shadow", // A private field (or class parameter) shadows a superclass field. 104 | "-Xlint:stars-align", // Pattern sequence wildcard must align with sequence component. 105 | "-Xlint:type-parameter-shadow", // A local type parameter shadows a type already in scope. 106 | ) 107 | 108 | // The REPL can’t cope with -Ywarn-unused:imports or -Xfatal-warnings so turn them off for the console 109 | scalacOptions in (Compile, console) --= Seq("-Ywarn-unused:imports", "-Xfatal-warnings") 110 | 111 | scalacOptions in (Compile, doc) ++= baseDirectory.map { bd: File => 112 | Seq[String]( 113 | "-sourcepath", bd.getAbsolutePath, 114 | "-doc-source-url", "https://github.com/mslinn/web3j-scala/tree/master€{FILE_PATH}.scala" 115 | ) 116 | }.value 117 | 118 | scalaVersion := "2.13.1" 119 | 120 | unmanagedSourceDirectories in Test ++= Seq( 121 | baseDirectory.value / "abiWrapper", 122 | baseDirectory.value / "demo" 123 | ) 124 | 125 | version := web3jVersion 126 | -------------------------------------------------------------------------------- /core-4.5.16.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | org.web3j 6 | core 7 | 4.5.16 8 | web3j 9 | web3j is a lightweight Java library for integration with Ethereum clients 10 | https://web3j.io 11 | 12 | 13 | The Apache License, Version 2.0 14 | http://www.apache.org/licenses/LICENSE-2.0.txt 15 | 16 | 17 | 18 | 19 | conor10 20 | Conor Svensson 21 | conor10@gmail.com 22 | 23 | 24 | antonydenyer 25 | Antony Denyer 26 | antony@web3labs.com 27 | 28 | 29 | 30 | scm:https://github.com/web3j/web3j.git 31 | scm:git://github.com/web3j/web3j.git 32 | https://github.com/web3j/web3j 33 | 34 | 35 | 36 | org.web3j 37 | abi 38 | 4.5.16 39 | compile 40 | 41 | 42 | org.web3j 43 | crypto 44 | 4.5.16 45 | compile 46 | 47 | 48 | org.web3j 49 | tuples 50 | 4.5.16 51 | compile 52 | 53 | 54 | com.github.jnr 55 | jnr-unixsocket 56 | 0.21 57 | compile 58 | 59 | 60 | com.squareup.okhttp3 61 | okhttp 62 | 4.3.1 63 | compile 64 | 65 | 66 | com.squareup.okhttp3 67 | logging-interceptor 68 | 4.3.1 69 | compile 70 | 71 | 72 | io.reactivex.rxjava2 73 | rxjava 74 | 2.2.2 75 | compile 76 | 77 | 78 | org.java-websocket 79 | Java-WebSocket 80 | 1.3.8 81 | compile 82 | 83 | 84 | com.fasterxml.jackson.core 85 | jackson-databind 86 | 2.8.5 87 | compile 88 | 89 | 90 | org.slf4j 91 | slf4j-api 92 | 1.7.25 93 | compile 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /demo/Demo.scala: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | import java.math.BigInteger 4 | import com.micronautics.web3j.{Cmd, Ether, EthereumSynchronous, Web3JScala} 5 | import Cmd.{isMac, isWindows} 6 | import org.web3j.protocol.Web3j 7 | import org.web3j.protocol.ipc.{UnixIpcService, WindowsIpcService} 8 | import scala.concurrent.duration.Duration 9 | import scala.concurrent.{Await, ExecutionContext, Promise} 10 | import org.web3j.protocol.core.DefaultBlockParameterName._ 11 | 12 | object Demo { 13 | val gasPrice: Ether = Ether(1) 14 | val gasLimit: BigInteger = BigInt(2).bigInteger 15 | 16 | val walletDir: String = Cmd.home( 17 | if (isWindows) s"${ sys.props("user.home") }\\AppData\\Roaming\\Ethereum\\" 18 | else if (isMac) "~/Library/Ethereum/" 19 | else "~/.ethereum/" 20 | ) 21 | } 22 | 23 | class Demo(implicit ec: ExecutionContext) { 24 | // Setup for running command lines from Scala 25 | val cmd = new Cmd() 26 | 27 | // Instantiate an instance of the underlying Web3J library: 28 | val web3j: Web3j = Web3JScala.fromHttp() // defaults to http://localhost:8545/ 29 | val web3jScala: Web3JScala = new Web3JScala(web3j) 30 | 31 | // Example of a synchronous request: 32 | val web3ClientVersion1: String = web3jScala.sync.versionWeb3J 33 | println(s"Web3J version = $web3ClientVersion1") 34 | 35 | // Contrived example of an asynchronous request, which provides no benefit over using a synchronous request: 36 | val web3ClientVersion2: String = Await.result(web3jScala.async.versionWeb3J, Duration.Inf) 37 | println(s"Web3J version = $web3ClientVersion2") 38 | 39 | // Better example of an asynchronous request: 40 | private val promise: Promise[String] = Promise[String] 41 | web3jScala.async.versionWeb3J.foreach { web3ClientVersion => 42 | println(s"Web3J version = $web3ClientVersion") 43 | promise.complete(scala.util.Success("Done")) 44 | } 45 | Await.ready(promise.future, Duration.Inf) // pause while the async request completes 46 | 47 | val eSync: EthereumSynchronous = web3jScala.sync 48 | eSync.accounts match { 49 | case Nil => println("No accounts found.") 50 | case accounts => 51 | accounts.foreach { 52 | account => println(s"The balance of $account is ${ eSync.balance(account, LATEST) } Wei") 53 | } 54 | } 55 | 56 | val ethereumDir: String = Cmd.home( 57 | if (isWindows) "~/AppData/Roaming/Ethereum" 58 | else if (isMac) "~/Library/Ethereum/" 59 | else "~/.ethereum/" 60 | ) + "devnet/" // todo discover the ethereum name at runtime 61 | 62 | // Web3J supports fast inter-process communication (IPC) via file sockets to clients running on the same host as Web3J. 63 | // To connect simply use the relevant IpcService implementation instead of HttpService when you create your service: 64 | val web3J3: Web3j = try { 65 | if (isWindows) 66 | Web3j.build(new WindowsIpcService(ethereumDir)) 67 | else 68 | Web3j.build(new UnixIpcService(ethereumDir + "geth.ipc")) 69 | } catch { 70 | case e: Throwable => 71 | System.err.println(e.getMessage) 72 | web3j 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /demo/DemoObservables.scala: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | import com.micronautics.web3j._ 4 | import com.micronautics.web3j.Web3JScala._ 5 | import org.web3j.protocol.core.DefaultBlockParameterName._ 6 | import org.web3j.protocol.core.methods.{request, response} 7 | 8 | /** Web3J's functional-reactive nature makes it easy to set up observers that notify subscribers of events taking place on the blockchain. 9 | * The functional-reactive programming style works really well with Scala. 10 | * 11 | * Other transaction and block replay [[org.web3j.utils.Flowables]] are described in [[https://docs.web3j.io/filters.html Filters and Events]]. */ 12 | class DemoObservables(demo: Demo) { 13 | import demo._ 14 | 15 | // Display the first 2 new blocks as they are added to the blockchain: 16 | observe(2)(web3j.blockFlowable(false)) { ethBlock => 17 | println(format(ethBlock)) 18 | } 19 | 20 | // Display only the first 2 new transactions as they are added to the blockchain: 21 | observe(2)(web3j.transactionFlowable) { tx => 22 | println(format(tx)) 23 | } 24 | 25 | // Display the first 2 pending transactions as they are submitted to the network, before they have been grouped into a block: 26 | observe(2)(web3j.pendingTransactionFlowable) { tx => 27 | println(format(tx)) 28 | } 29 | 30 | // Replay all blocks to the most current, and be notified of new subsequent blocks being created 31 | // Display minimal information about old blocks, show detailed information for new blocks 32 | val now: Long = System.currentTimeMillis 33 | var count = 0 34 | web3j.replayPastAndFutureBlocksFlowable(EARLIEST, false).subscribe { ethBlock => 35 | val block = ethBlock.getBlock 36 | if (block.getTimestamp.longValue 58 | println(format(log)) 59 | } 60 | 61 | 62 | protected def format(ethBlock: response.EthBlock): String = { 63 | val block = ethBlock.getBlock 64 | s"""ETH block: 65 | | Author = ${ block.getAuthor } 66 | | Bloom logs = ${ block.getLogsBloom } 67 | | Difficulty = ${ block.getDifficulty } 68 | | Extra data = ${ block.getExtraData } 69 | | Gas limit = ${ block.getGasLimit } 70 | | Gas used = ${ block.getGasUsed } 71 | | Hash = ${ block.getHash } 72 | | Java time = ${ block.javaTime } 73 | | Miner = ${ block.getMiner } 74 | | Mix hash = ${ block.getMixHash } 75 | | Nonce = ${ block.getNonce } 76 | | Number = ${ block.getNumber } 77 | | Parent hash = ${ block.getParentHash } 78 | | Receipts root = ${ block.getReceiptsRoot } 79 | | Seal fields = ${ block.getSealFields } 80 | | SHA3 uncles = ${ block.getSha3Uncles } 81 | | Size = ${ block.getSize } 82 | | State root = ${ block.getStateRoot } 83 | | Timestamp = ${ block.getTimestamp } 84 | | Transactions.size = ${ block.getTransactions.size } 85 | | Transactions root = ${ block.getTransactionsRoot } 86 | | Uncles = ${ block.getUncles } 87 | | Raw difficulty = ${ block.getDifficultyRaw } 88 | | Raw gas limit = ${ block.getGasLimitRaw } 89 | | Raw gas used = ${ block.getGasUsedRaw } 90 | | Raw nonce = ${ block.getNonceRaw } 91 | | Raw number = ${ block.getNumberRaw } 92 | | Raw size = ${ block.getSizeRaw } 93 | | Raw timestamp = ${ block.getTimestampRaw} 94 | | Total difficulty = ${ block.getTotalDifficulty } 95 | | Raw total difficulty = ${ block.getTotalDifficultyRaw } 96 | |""".stripMargin 97 | } 98 | 99 | protected def format(log: response.Log): String = 100 | s"""Response Log: 101 | | Address = ${ log.getAddress } 102 | | Block hash = ${ log.getBlockHash } 103 | | Block number = ${ log.getBlockNumber } 104 | | Data = ${ log.getData } 105 | | Log index = ${ log.getLogIndex } 106 | | Topics = ${ log.getTopics } 107 | | Transaction hash = ${ log.getTransactionHash } 108 | | Transaction index = ${ log.getTransactionIndex } 109 | | Type = ${ log.getType } 110 | | Removed = ${ log.isRemoved } 111 | | Raw block number = ${ log.getBlockNumberRaw } 112 | | Raw log index = ${ log.getLogIndexRaw } 113 | | Raw transaction index = ${ log.getTransactionIndexRaw } 114 | |""".stripMargin 115 | 116 | protected def format(tx: response.Transaction): String = 117 | s"""Transaction: 118 | | Block hash = ${ tx.getBlockHash } 119 | | Block number = ${ tx.getBlockNumber } 120 | | Block number raw = ${ tx.getBlockNumberRaw } 121 | | Creates = ${ tx.getCreates } 122 | | From = ${ tx.getFrom } 123 | | Gas = ${ tx.getGas } 124 | | Gas price = ${ tx.getGasPrice } 125 | | Hash = ${ tx.getHash } 126 | | Input = ${ tx.getInput } 127 | | Nonce = ${ tx.getNonce } 128 | | Public key = ${ tx.getPublicKey } 129 | | R = ${ tx.getR } 130 | | To = ${ tx.getTo } 131 | | Transaction index = ${ tx.getTransactionIndex } 132 | | V = ${ tx.getV } 133 | | Value = ${ tx.getValue } 134 | | Raw = ${ tx.getRaw } 135 | | Raw gas = ${ tx.getGasRaw } 136 | | Raw gas price = ${ tx.getGasPriceRaw } 137 | | Raw nonce = ${ tx.getNonceRaw } 138 | | Raw transaction index = ${ tx.getTransactionIndexRaw } 139 | | Raw value = ${ tx.getValueRaw } 140 | |""".stripMargin 141 | } 142 | -------------------------------------------------------------------------------- /demo/DemoSmartContracts.scala: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | import org.web3j.crypto.{Credentials, WalletUtils} 4 | import org.web3j.protocol.core.RemoteCall 5 | 6 | object CreateSmartContracts extends App { 7 | import scala.concurrent.ExecutionContext.Implicits.global 8 | 9 | new DemoSmartContracts(new Demo) 10 | } 11 | 12 | /** Web3J can auto-generate smart contract wrapper code to deploy and interact with smart contracts without leaving the JVM. 13 | * This program creates a smart contract wrapper around a [[../src/test/resources/basic_info_getter.sol sample smart contract]] 14 | * and demonstrates how to work with smart contracts using JVM wrappers. 15 | * 16 | * Run this program before [[Main running the demo]]. 17 | * 18 | * @see See [[https://web3j.readthedocs.io/en/latest/smart_contracts.html Web3J Smart Contracts]] */ 19 | class DemoSmartContracts(demo: Demo) { 20 | import com.micronautics.web3j.Web3JScala.{solc,wrapAbi} 21 | import com.micronautics.solidity._ 22 | import Demo._ 23 | 24 | // Compile the smart contract before generating the wrapper code 25 | println(solc("src/test/resources/basic_info_getter.sol")) 26 | println(wrapAbi("basic_info_getter")) 27 | 28 | try { 29 | val credentials: Credentials = WalletUtils.loadCredentials("password", walletDir) 30 | 31 | val basicInfoGetter: RemoteCall[BasicInfoGetter] = BasicInfoGetter.deploy(demo.web3j, credentials, gasPrice.bigInteger, gasLimit) 32 | val x: BasicInfoGetter = basicInfoGetter.send 33 | println(x) 34 | 35 | // Or use an existing contract: 36 | // val contract2 = YourSmartContract.load( "0x
", web3j, credentials, gasPrice, gasLimit) 37 | 38 | // Transact with a smart contract 39 | // val result = basicInfoGetter.send().getContractAddress.send() 40 | // println(s"basicInfoGetter.getContractAddress = $result") 41 | } catch { 42 | case e: Throwable => 43 | System.err.println(e.getMessage) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /demo/DemoTransaction.scala: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | import java.math.BigInteger 4 | import com.micronautics.web3j.{Address, Nonce} 5 | import org.web3j.crypto.{Credentials, RawTransaction, TransactionEncoder, WalletUtils} 6 | import org.web3j.protocol.admin.Admin 7 | import org.web3j.protocol.admin.methods.response.PersonalUnlockAccount 8 | import org.web3j.protocol.core.DefaultBlockParameterName._ 9 | import org.web3j.protocol.core.methods.response.TransactionReceipt 10 | import org.web3j.protocol.http.HttpService 11 | import org.web3j.tx.Transfer 12 | import org.web3j.utils.Convert.Unit.{ETHER, WEI} 13 | 14 | /** Web3J provides support for both working with Ethereum wallet files (recommended) and Ethereum client admin commands 15 | * for sending transactions. */ 16 | class DemoTransaction(demo: Demo) { 17 | import Demo._, demo._ 18 | 19 | // Send Ether to another party using your Ethereum wallet file 20 | val credentials: Credentials = WalletUtils.loadCredentials("password", walletDir) 21 | val transactionReceipt: TransactionReceipt = 22 | Transfer.sendFunds(web3j, credentials, "0x...", BigDecimal.valueOf(0.01).bigDecimal, ETHER).send 23 | println(format(transactionReceipt)) 24 | 25 | // Before creating a custom transaction, first get the next available nonce 26 | val nonce: Nonce = demo.web3jScala.sync.nextNonce(Address("address")) 27 | 28 | // Create a custom transaction 29 | val rawTransaction: RawTransaction = 30 | RawTransaction.createEtherTransaction(nonce.bigInteger, gasPrice.bigInteger, gasLimit, "toAddress", BigInt(1).bigInteger) 31 | println(format(rawTransaction)) 32 | 33 | // Sign & send the transaction 34 | val signedMessage: Array[Byte] = TransactionEncoder.signMessage(rawTransaction, credentials) 35 | val hexValue: String = javax.xml.bind.DatatypeConverter.printHexBinary(signedMessage) 36 | val transactionHash: String = web3j.ethSendRawTransaction(hexValue).send.getTransactionHash 37 | 38 | // Now let's transfer some funds. Be sure a wallet is available in the client’s keystore. TODO how? 39 | // One option is to use web3j’s `Transfer` class for transacting with Ether. 40 | Transfer.sendFunds(web3j, credentials, "toAddress", BigDecimal(1).bigDecimal, WEI) 41 | 42 | // Here is how to use the Ethereum client’s admin commands: 43 | val web3jAdmin: Admin = Admin.build(new HttpService) 44 | val personalUnlockAccount: PersonalUnlockAccount = web3jAdmin.personalUnlockAccount("0x000...", "a password").sendAsync.get 45 | if (personalUnlockAccount.accountUnlocked) { 46 | // todo send a transaction 47 | } 48 | 49 | // Todo demonstrate the use of Parity’s Personal, Trace, or geth’s personal client APIs, by using the org.web3j:parity and org.web3j:geth modules respectively. 50 | 51 | protected def format(tx: RawTransaction): String = 52 | s"""Raw transaction: 53 | | Data = ${ tx.getData } 54 | | Gas limit = ${ tx.getGasLimit } 55 | | Gas price = ${ tx.getGasPrice } 56 | | Gas limit = ${ tx.getGasLimit } 57 | | Nonce = ${ tx.getNonce } 58 | | To = ${ tx.getTo } 59 | | Value = ${ tx.getValue } 60 | |""".stripMargin 61 | 62 | protected def format(tx: TransactionReceipt): String = 63 | s"""Transaction receipt: 64 | | Block hash = ${ tx.getBlockHash } 65 | | Block number = ${ tx.getBlockNumber } 66 | | Raw block number = ${ tx.getBlockNumberRaw } 67 | | Contract address = ${ tx.getContractAddress } 68 | | Cumulative gas used = ${ tx.getCumulativeGasUsed } 69 | | Raw cumulative gas used = ${ tx.getCumulativeGasUsedRaw } 70 | | From = ${ tx.getFrom } 71 | | Gas used = ${ tx.getGasUsed } 72 | | Raw gas used = ${ tx.getGasUsedRaw } 73 | | Logs = ${ tx.getLogs } 74 | | Log bloom = ${ tx.getLogsBloom } 75 | | Root = ${ tx.getRoot } 76 | | To = ${ tx.getTo } 77 | | Transaction hash = ${ tx.getTransactionHash } 78 | | Transaction index = ${ tx.getTransactionIndex } 79 | | Raw transaction index = ${ tx.getTransactionIndexRaw } 80 | |""".stripMargin 81 | } 82 | -------------------------------------------------------------------------------- /demo/Main.scala: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | /** Adapted from [[https://docs.web3j.io/getting_started.html#start-a-client Web3J Getting Started]]. 4 | * 5 | * 1. Before running this program, start up an Ethereum client if you don’t already have one running, such as `geth`: 6 | * {{{$ geth --rpcapi personal,db,eth,net,web3 --rpc --rinkeby --ipcpath "geth.ipc"}}} 7 | * 8 | * 2. Create the smart contract JVM wrapper by running `CreateSmartContracts` defined in `demo/DemoSmartContracts.scala`: 9 | * {{{$ sbt "test:runMain demo.CreateSmartContracts"}}} 10 | * 11 | * 3. Run this program by typing the following at a shell prompt: 12 | * {{{$ sbt "test:runMain demo.Main"}}} */ 13 | object Main extends App { 14 | import scala.concurrent.ExecutionContext.Implicits.global 15 | 16 | val demo = new Demo 17 | new DemoObservables(demo) 18 | new DemoSmartContracts(demo) 19 | new DemoTransaction(demo) 20 | } 21 | -------------------------------------------------------------------------------- /geth.md: -------------------------------------------------------------------------------- 1 | ``` 2 | $ geth -h 3 | NAME: 4 | geth - the go-ethereum command line interface 5 | 6 | Copyright 2013-2017 The go-ethereum Authors 7 | 8 | USAGE: 9 | geth [options] command [command options] [arguments...] 10 | 11 | VERSION: 12 | 1.7.3-unstable-9619a610 13 | 14 | COMMANDS: 15 | account Manage accounts 16 | attach Start an interactive JavaScript environment (connect to node) 17 | bug opens a window to report a bug on the geth repo 18 | console Start an interactive JavaScript environment 19 | copydb Create a local chain from a target chaindata folder 20 | dump Dump a specific block from storage 21 | dumpconfig Show configuration values 22 | export Export blockchain into file 23 | import Import a blockchain file 24 | init Bootstrap and initialize a new genesis block 25 | js Execute the specified JavaScript files 26 | license Display license information 27 | makecache Generate ethash verification cache (for testing) 28 | makedag Generate ethash mining DAG (for testing) 29 | monitor Monitor and visualize node metrics 30 | removedb Remove blockchain and state databases 31 | version Print version numbers 32 | wallet Manage Ethereum presale wallets 33 | help, h Shows a list of commands or help for one command 34 | 35 | ETHEREUM OPTIONS: 36 | --config value TOML configuration file 37 | --datadir "/home/mslinn/.ethereum" Data directory for the databases and keystore 38 | --keystore Directory for the keystore (default = inside the datadir) 39 | --nousb Disables monitoring for and managing USB hardware wallets 40 | --networkid value Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby) (default: 1) 41 | --testnet Ropsten network: pre-configured proof-of-work test network 42 | --rinkeby Rinkeby network: pre-configured proof-of-authority test network 43 | --syncmode "fast" Blockchain sync mode ("fast", "full", or "light") 44 | --ethstats value Reporting URL of a ethstats service (nodename:secret@host:port) 45 | --identity value Custom node name 46 | --lightserv value Maximum percentage of time allowed for serving LES requests (0-90) (default: 0) 47 | --lightpeers value Maximum number of LES client peers (default: 20) 48 | --lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength 49 | 50 | DEVELOPER CHAIN OPTIONS: 51 | --dev Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled 52 | --dev.period value Block period to use in developer mode (0 = mine only if transaction pending) (default: 0) 53 | 54 | ETHASH OPTIONS: 55 | --ethash.cachedir Directory to store the ethash verification caches (default = inside the datadir) 56 | --ethash.cachesinmem value Number of recent ethash caches to keep in memory (16MB each) (default: 2) 57 | --ethash.cachesondisk value Number of recent ethash caches to keep on disk (16MB each) (default: 3) 58 | --ethash.dagdir "/home/mslinn/.ethash" Directory to store the ethash mining DAGs (default = inside home folder) 59 | --ethash.dagsinmem value Number of recent ethash mining DAGs to keep in memory (1+GB each) (default: 1) 60 | --ethash.dagsondisk value Number of recent ethash mining DAGs to keep on disk (1+GB each) (default: 2) 61 | 62 | TRANSACTION POOL OPTIONS: 63 | --txpool.nolocals Disables price exemptions for locally submitted transactions 64 | --txpool.journal value Disk journal for local transaction to survive node restarts (default: "transactions.rlp") 65 | --txpool.rejournal value Time interval to regenerate the local transaction journal (default: 1h0m0s) 66 | --txpool.pricelimit value Minimum gas price limit to enforce for acceptance into the pool (default: 1) 67 | --txpool.pricebump value Price bump percentage to replace an already existing transaction (default: 10) 68 | --txpool.accountslots value Minimum number of executable transaction slots guaranteed per account (default: 16) 69 | --txpool.globalslots value Maximum number of executable transaction slots for all accounts (default: 4096) 70 | --txpool.accountqueue value Maximum number of non-executable transaction slots permitted per account (default: 64) 71 | --txpool.globalqueue value Maximum number of non-executable transaction slots for all accounts (default: 1024) 72 | --txpool.lifetime value Maximum amount of time non-executable transaction are queued (default: 3h0m0s) 73 | 74 | PERFORMANCE TUNING OPTIONS: 75 | --cache value Megabytes of memory allocated to internal caching (min 16MB / database forced) (default: 128) 76 | --trie-cache-gens value Number of trie node generations to keep in memory (default: 120) 77 | 78 | ACCOUNT OPTIONS: 79 | --unlock value Comma separated list of accounts to unlock 80 | --password value Password file to use for non-interactive password input 81 | 82 | API AND CONSOLE OPTIONS: 83 | --rpc Enable the HTTP-RPC server 84 | --rpcaddr value HTTP-RPC server listening interface (default: "localhost") 85 | --rpcport value HTTP-RPC server listening port (default: 8545) 86 | --rpcapi value API's offered over the HTTP-RPC interface 87 | --ws Enable the WS-RPC server 88 | --wsaddr value WS-RPC server listening interface (default: "localhost") 89 | --wsport value WS-RPC server listening port (default: 8546) 90 | --wsapi value API's offered over the WS-RPC interface 91 | --wsorigins value Origins from which to accept websockets requests 92 | --ipcdisable Disable the IPC-RPC server 93 | --ipcpath Filename for IPC socket/pipe within the datadir (explicit paths escape it) 94 | --rpccorsdomain value Comma separated list of domains from which to accept cross origin requests (browser enforced) 95 | --jspath loadScript JavaScript root path for loadScript (default: ".") 96 | --exec value Execute JavaScript statement 97 | --preload value Comma separated list of JavaScript files to preload into the console 98 | 99 | NETWORKING OPTIONS: 100 | --bootnodes value Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers) 101 | --bootnodesv4 value Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes) 102 | --bootnodesv5 value Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes) 103 | --port value Network listening port (default: 30303) 104 | --maxpeers value Maximum number of network peers (network disabled if set to 0) (default: 25) 105 | --maxpendpeers value Maximum number of pending connection attempts (defaults used if set to 0) (default: 0) 106 | --nat value NAT port mapping mechanism (any|none|upnp|pmp|extip:) (default: "any") 107 | --nodiscover Disables the peer discovery mechanism (manual peer addition) 108 | --v5disc Enables the experimental RLPx V5 (Topic Discovery) mechanism 109 | --netrestrict value Restricts network communication to the given IP networks (CIDR masks) 110 | --nodekey value P2P node key file 111 | --nodekeyhex value P2P node key as hex (for testing) 112 | 113 | MINER OPTIONS: 114 | --mine Enable mining 115 | --minerthreads value Number of CPU threads to use for mining (default: 8) 116 | --etherbase value Public address for block mining rewards (default = first account created) (default: "0") 117 | --targetgaslimit value Target gas limit sets the artificial target gas floor for the blocks to mine (default: 4712388) 118 | --gasprice "18000000000" Minimal gas price to accept for mining a transactions 119 | --extradata value Block extra data set by the miner (default = client version) 120 | 121 | GAS PRICE ORACLE OPTIONS: 122 | --gpoblocks value Number of recent blocks to check for gas prices (default: 10) 123 | --gpopercentile value Suggested gas price is the given percentile of a set of recent transaction gas prices (default: 50) 124 | 125 | VIRTUAL MACHINE OPTIONS: 126 | --vmdebug Record information useful for VM and contract debugging 127 | 128 | LOGGING AND DEBUGGING OPTIONS: 129 | --metrics Enable metrics collection and reporting 130 | --fakepow Disables proof-of-work verification 131 | --nocompaction Disables db compaction after import 132 | --verbosity value Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default: 3) 133 | --vmodule value Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4) 134 | --backtrace value Request a stack trace at a specific logging statement (e.g. "block.go:271") 135 | --debug Prepends log messages with call-site location (file and line number) 136 | --pprof Enable the pprof HTTP server 137 | --pprofaddr value pprof HTTP server listening interface (default: "127.0.0.1") 138 | --pprofport value pprof HTTP server listening port (default: 6060) 139 | --memprofilerate value Turn on memory profiling with the given rate (default: 524288) 140 | --blockprofilerate value Turn on block profiling with the given rate (default: 0) 141 | --cpuprofile value Write CPU profile to the given file 142 | --trace value Write execution trace to the given file 143 | 144 | WHISPER (EXPERIMENTAL) OPTIONS: 145 | --shh Enable Whisper 146 | --shh.maxmessagesize value Max message size accepted (default: 1048576) 147 | --shh.pow value Minimum POW accepted (default: 0.2) 148 | 149 | DEPRECATED OPTIONS: 150 | --fast Enable fast syncing through state downloads 151 | --light Enable light client mode 152 | 153 | MISC OPTIONS: 154 | --help, -h show help 155 | 156 | 157 | COPYRIGHT: 158 | Copyright 2013-2017 The go-ethereum Authors 159 | ``` 160 | -------------------------------------------------------------------------------- /logos/repository-open-graph-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mslinn/web3j-scala/d93644861655c27446858d638d53c63007699211/logos/repository-open-graph-template.png -------------------------------------------------------------------------------- /logos/repository-open-graph.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mslinn/web3j-scala/d93644861655c27446858d638d53c63007699211/logos/repository-open-graph.ai -------------------------------------------------------------------------------- /logos/repository-open-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mslinn/web3j-scala/d93644861655c27446858d638d53c63007699211/logos/repository-open-graph.png -------------------------------------------------------------------------------- /logos/web3j-orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mslinn/web3j-scala/d93644861655c27446858d638d53c63007699211/logos/web3j-orange.png -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.3.9 2 | -------------------------------------------------------------------------------- /project/build.sbt: -------------------------------------------------------------------------------- 1 | libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3" 2 | -------------------------------------------------------------------------------- /project/ghpages.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.4.0") 2 | addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.3") 3 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | // See https://github.com/rtimush/sbt-updates 2 | addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.5.0") 3 | 4 | // See https://github.com/sbt/sbt-assembly 5 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.10") 6 | 7 | // See https://github.com/sbt/sbt-bintray 8 | resolvers += Resolver.jcenterRepo 9 | addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.6") 10 | 11 | // See https://github.com/ThoughtWorksInc/sbt-api-mappings 12 | addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.0") 13 | -------------------------------------------------------------------------------- /publish.sbt: -------------------------------------------------------------------------------- 1 | import scala.sys.process._ 2 | 3 | lazy val scaladoc = 4 | taskKey[Unit]("Rebuilds the Scaladoc and pushes the updated Scaladoc to GitHub pages without committing to the git repository") 5 | 6 | scaladoc := { 7 | println("Creating Scaladoc") 8 | doc.in(Test).value 9 | 10 | println("Uploading Scaladoc to GitHub Pages") 11 | ghpagesPushSite.value 12 | } 13 | 14 | /** Best practice is to comment your commits before invoking this task: `git commit -am "Your comment here"`. 15 | * This task does the following: 16 | * 1. `git pull` when it starts. 17 | * 2. Attempts to build Scaladoc, which fails if there is a compile error 18 | * 3. Ensures any uncommitted changes are committed before publishing, including new files; it provides the comment as "-". 19 | * 4. Git pushes all files 20 | * 5. Uploads new Scaladoc 21 | * 6. Publishes new version to Bintray */ 22 | lazy val commitAndDoc = 23 | taskKey[Unit]("Rebuilds the docs, commits the git repository, and publishes the updated Scaladoc without publishing a new version") 24 | 25 | commitAndDoc := { 26 | try { 27 | println("Fetching latest updates for this git repo") 28 | "git pull".!! 29 | 30 | println("Creating Scaladoc") 31 | doc.in(Test).value 32 | 33 | val changedFileNames: String = "git diff --name-only".!!.trim.replace("\n", ", ") 34 | if (changedFileNames.nonEmpty) { 35 | println(s"About to commit these changed files: $changedFileNames") 36 | "git add -A".!! 37 | "git commit -m -".!! 38 | } 39 | 40 | /*val stagedFileNames = "git diff --cached --name-only".!!.trim.replace("\n", ", ") 41 | if (stagedFileNames.nonEmpty) { 42 | println(s"About to push these staged files: $stagedFileNames") 43 | }*/ 44 | 45 | println("About to git push to origin") 46 | "git push origin HEAD".!! // See https://stackoverflow.com/a/20922141/553865 47 | 48 | println("Uploading Scaladoc to GitHub Pages") 49 | ghpagesPushSite.value 50 | } catch { 51 | case e: Exception => println(e.getMessage) 52 | } 53 | () 54 | } 55 | 56 | /** Publish a new version of this library to BinTray. 57 | * Be sure to update the version string in build.sbt before running this task. */ 58 | lazy val publishAndTag = 59 | taskKey[Unit]("Invokes commitAndPublish, then creates a git tag for the version string defined in build.sbt") 60 | 61 | publishAndTag := { 62 | commitAndDoc.in(Compile).value 63 | publish.value 64 | println(s"Creating git tag for v${ version.value }") 65 | s"""git tag -a ${ version.value } -m ${ version.value }""".!! 66 | s"""git push origin --tags""".!! 67 | () 68 | } 69 | 70 | // See http://www.scala-sbt.org/1.0/docs/Howto-Scaladoc.html 71 | autoAPIMappings := true 72 | apiURL := Some(url("https://mslinn.github.io/web3j-scala/latest/api")) 73 | 74 | bintrayOrganization := Some("micronautics") 75 | bintrayRepository := "scala" 76 | bintrayPackage := "web3j-scala" 77 | 78 | // sbt-site settings 79 | enablePlugins(SiteScaladocPlugin) 80 | siteSourceDirectory := target.value / "api" 81 | publishSite 82 | 83 | // sbt-ghpages settings 84 | enablePlugins(GhpagesPlugin) 85 | git.remoteRepo := s"git@github.com:mslinn/${ name.value }.git" 86 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/scala/com/micronautics/web3j/Cmd.scala: -------------------------------------------------------------------------------- 1 | package com.micronautics.web3j 2 | 3 | import java.io.File 4 | import java.nio.file.{Files, Path, Paths} 5 | import java.util.regex.Pattern 6 | import org.slf4j.Logger 7 | import scala.sys.process._ 8 | 9 | /** Command-line invocation / process control */ 10 | object Cmd { 11 | val logger: Logger = org.slf4j.LoggerFactory.getLogger("gitStats") 12 | 13 | protected lazy val os: String = sys.props("os.name").toLowerCase 14 | 15 | lazy val isWindows: Boolean = os.indexOf("win") >= 0 16 | lazy val isMac: Boolean = os.toLowerCase.startsWith("mac os x") 17 | lazy val isLinux: Boolean = os.toLowerCase.startsWith("linux") 18 | 19 | protected def which(program: String): Option[Path] = { 20 | val path = if (isWindows) sys.env("Path") else sys.env("PATH") 21 | path 22 | .split(Pattern.quote(File.pathSeparator)) 23 | .map(Paths.get(_)) 24 | .find(path => Files.exists(path.resolve(program))) 25 | .map(_.resolve(program)).orElse( 26 | Paths.get("").resolve(program) match { 27 | case path if Files.exists(path) => Some(path) 28 | case _ => None 29 | } 30 | ) 31 | } 32 | 33 | @inline protected def whichOrThrow(program: String): Path = 34 | which(program) match { 35 | case None => sys.error(program + " not found on PATH") 36 | case Some(programPath) => programPath 37 | } 38 | 39 | @inline def home(path: String): String = path.replace("~", sys.props("user.home")) 40 | } 41 | 42 | class Cmd(cwd: File = new File("."), showOutput: Boolean=true, verbose: Boolean=false) { 43 | import Cmd._ 44 | 45 | @inline def apply(cmd: String*): ProcessBuilder = { 46 | val command: List[String] = whichOrThrow(cmd(0)).toString :: cmd.tail.toList.map(home) 47 | if (verbose) println(s"[${ cwd.getAbsolutePath }] " + command.mkString(" ")) 48 | Process(command=command, cwd=cwd) 49 | } 50 | 51 | @inline def getOutputFrom(cmd: String*): String = 52 | try { 53 | val result = apply(cmd:_*).!!.trim 54 | if (showOutput) println(result) 55 | result 56 | } catch { 57 | case e: Exception => 58 | Console.err.println(e.getMessage) 59 | if (null!=e.getCause && e.getCause.toString.nonEmpty) Console.err.println(e.getCause) 60 | Console.err.println(e.getStackTrace.mkString("\n")) 61 | sys.exit(-1) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/scala/com/micronautics/web3j/Ether.scala: -------------------------------------------------------------------------------- 1 | package com.micronautics.web3j 2 | 3 | object Ether { 4 | lazy val zero: Ether = Ether(0) 5 | 6 | /** @return a BigInt containing 1 with the given number of zeros after it, e.g. {{{e(3) == BigInt(1000)}}} */ 7 | @inline def e(howManyZeros: Int): BigInt = BigInt(s"1${ zeros(howManyZeros) }") 8 | 9 | /** @return a String containing the specified number of zeros, e.g. {{{zeros(3) == "000"}}} */ 10 | @inline def zeros(howMany: Int): String = "0" * howMany 11 | 12 | /** @param value unit is wei */ 13 | @inline def apply(value: String): Ether = new Ether(BigInt(value)) 14 | @inline def apply(value: BigInt): Ether = new Ether(value) 15 | @inline def apply(value: Int): Ether = new Ether(BigInt(value)) 16 | @inline def apply(value: Double): Ether = new Ether(BigDecimal(value).bigDecimal.toBigInteger) 17 | @inline def apply(value: BigDecimal): Ether = new Ether(value.bigDecimal.toBigInteger) 18 | 19 | @inline def fromWei(value: String): Ether = Ether(value) 20 | @inline def fromWei(value: Double): Ether = Ether(value) 21 | @inline def fromWei(value: BigDecimal): Ether = Ether(value) 22 | @inline def fromWei(value: Int): Ether = Ether(value) 23 | @inline def fromWei(value: BigInt): Ether = Ether(value) 24 | 25 | @inline def fromKWei(value: String): Ether = Ether(value + zeros(3)) 26 | @inline def fromKWei(value: Double): Ether = Ether(BigDecimal(value) * BigDecimal(e(3))) 27 | @inline def fromKWei(value: BigDecimal): Ether = Ether(value * BigDecimal(e(3))) 28 | @inline def fromKWei(value: Int): Ether = Ether(value * e(3)) 29 | @inline def fromKWei(value: BigInt): Ether = Ether(value * e(3)) 30 | 31 | @inline def fromMWei(value: String): Ether = Ether(value + zeros(6)) 32 | @inline def fromMWei(value: Double): Ether = Ether(BigDecimal(value) * BigDecimal(e(6))) 33 | @inline def fromMWei(value: BigDecimal): Ether = Ether(value * BigDecimal(e(6))) 34 | @inline def fromMWei(value: Int): Ether = Ether(value * e(6)) 35 | @inline def fromMWei(value: BigInt): Ether = Ether(value * e(6)) 36 | 37 | @inline def fromGWei(value: String): Ether = Ether(value + zeros(9)) 38 | @inline def fromGWei(value: Double): Ether = Ether(BigDecimal(value) * BigDecimal(e(9))) 39 | @inline def fromGWei(value: BigDecimal): Ether = Ether(value * BigDecimal(e(9))) 40 | @inline def fromGWei(value: Int): Ether = Ether(value * e(9)) 41 | @inline def fromGWei(value: BigInt): Ether = Ether(value * e(9)) 42 | 43 | @inline def fromSzabo(value: String): Ether = Ether(value + zeros(12)) 44 | @inline def fromSzabo(value: Double): Ether = Ether(BigDecimal(value) * BigDecimal(e(12))) 45 | @inline def fromSzabo(value: BigDecimal): Ether = Ether(value * BigDecimal(e(12))) 46 | @inline def fromSzabo(value: Int): Ether = Ether(value * e(12)) 47 | @inline def fromSzabo(value: BigInt): Ether = Ether(value * e(12)) 48 | 49 | @inline def fromFinney(value: String): Ether = Ether(value + zeros(15)) 50 | @inline def fromFinney(value: Double): Ether = Ether(BigDecimal(value) * BigDecimal(e(15))) 51 | @inline def fromFinney(value: BigDecimal): Ether = Ether(value * BigDecimal(e(15))) 52 | @inline def fromFinney(value: Int): Ether = Ether(value * e(15)) 53 | @inline def fromFinney(value: BigInt): Ether = Ether(value * e(15)) 54 | 55 | @inline def fromEther(value: String): Ether = Ether(value + zeros(18)) 56 | @inline def fromEther(value: Double): Ether = Ether(BigDecimal(value) * BigDecimal(e(18))) 57 | @inline def fromEther(value: BigDecimal): Ether = Ether(value * BigDecimal(e(18))) 58 | @inline def fromEther(value: Int): Ether = Ether(value * e(18)) 59 | @inline def fromEther(value: BigInt): Ether = Ether(value * e(18)) 60 | 61 | @inline def fromKEther(value: String): Ether = Ether(value + zeros(21)) 62 | @inline def fromKEther(value: Double): Ether = Ether(BigDecimal(value) * BigDecimal(e(21))) 63 | @inline def fromKEther(value: BigDecimal): Ether = Ether(value * BigDecimal(e(21))) 64 | @inline def fromKEther(value: Int): Ether = Ether(value * e(21)) 65 | @inline def fromKEther(value: BigInt): Ether = Ether(value * e(21)) 66 | 67 | @inline def fromMEther(value: String): Ether = Ether(value + zeros(24)) 68 | @inline def fromMEther(value: Double): Ether = Ether(BigDecimal(value) * BigDecimal(e(24))) 69 | @inline def fromMEther(value: BigDecimal): Ether = Ether(value * BigDecimal(e(24))) 70 | @inline def fromMEther(value: Int): Ether = Ether(value * e(24)) 71 | @inline def fromMEther(value: BigInt): Ether = Ether(value * e(24)) 72 | 73 | @inline def fromGEther(value: String): Ether = Ether(value + zeros(27)) 74 | @inline def fromGEther(value: Double): Ether = Ether(BigDecimal(value) * BigDecimal(e(27))) 75 | @inline def fromGEther(value: BigDecimal): Ether = Ether(value * BigDecimal(e(27))) 76 | @inline def fromGEther(value: Int): Ether = Ether(value * e(27)) 77 | @inline def fromGEther(value: BigInt): Ether = Ether(value * e(27)) 78 | } 79 | 80 | /** Wei are the smallest unit of currency and are always integers, never fractional quantities */ 81 | class Ether(val wei: BigInt) extends Ordered[Ether] { 82 | import Ether._ 83 | 84 | @inline def *(value: Ether): Ether = Ether(wei * value.wei) 85 | @inline def *(value: Int): Ether = Ether(wei * value) 86 | @inline def *(value: Double): Ether = Ether(BigDecimal(wei) * value) 87 | @inline def *(value: BigInt): Ether = Ether(value) * wei 88 | @inline def *(value: BigDecimal): Ether = Ether(value) * wei 89 | 90 | @inline def /(value: Ether): Ether = Ether(wei / value.wei) 91 | @inline def /(value: Int): Ether = Ether(wei / value) 92 | @inline def /(value: Double): Ether = Ether(BigDecimal(wei) / value) 93 | @inline def /(value: BigInt): Ether = Ether(value) / wei 94 | @inline def /(value: BigDecimal): Ether = Ether(value) / wei 95 | 96 | @inline def +(value: Ether): Ether = Ether(wei + value.wei) 97 | @inline def +(value: Int): Ether = Ether(wei + value) 98 | @inline def +(value: Double): Ether = Ether(BigDecimal(wei) + value) 99 | @inline def +(value: BigInt): Ether = Ether(value) + wei 100 | @inline def +(value: BigDecimal): Ether = Ether(value) + wei 101 | 102 | @inline def -(value: Ether): Ether = Ether(wei - value.wei) 103 | @inline def -(value: Int): Ether = Ether(wei - value) 104 | @inline def -(value: Double): Ether = Ether(BigDecimal(wei) - value) 105 | @inline def -(value: BigInt): Ether = Ether(value) - wei 106 | @inline def -(value: BigDecimal): Ether = Ether(value) - wei 107 | 108 | @inline def bigInteger: java.math.BigInteger = wei.bigInteger 109 | @inline def asWei: BigInt = wei 110 | @inline def asKWei: BigDecimal = bigDecimal(wei / e(3)) 111 | @inline def asMWei: BigDecimal = bigDecimal(wei / e(6)) 112 | @inline def asGWei: BigDecimal = bigDecimal(wei / e(9)) 113 | @inline def asSzabo: BigDecimal = bigDecimal(wei / e(12)) 114 | @inline def asFinney: BigDecimal = bigDecimal(wei / e(15)) 115 | @inline def asEther: BigDecimal = bigDecimal(wei / e(18)) 116 | @inline def asKEther: BigDecimal = bigDecimal(wei / e(21)) 117 | @inline def asMEther: BigDecimal = bigDecimal(wei / e(24)) 118 | @inline def asGEther: BigDecimal = bigDecimal(wei / e(27)) 119 | 120 | /** @return Amount of Ether corresponding to the given wei value */ 121 | @inline def bigDecimal(wei: BigInt): java.math.BigDecimal = 122 | new java.math.BigDecimal(wei.bigInteger) 123 | .setScale(16, java.math.RoundingMode.DOWN) 124 | 125 | @inline def compare(that: Ether): Int = this.wei compare that.wei 126 | 127 | @inline override def equals(that: Any): Boolean = 128 | that match { 129 | case that: Ether => 130 | this.hashCode == that.hashCode 131 | 132 | case _ => false 133 | } 134 | 135 | @inline override def hashCode: Int = wei.hashCode 136 | 137 | @inline def isNegative: Boolean = wei < zero.wei 138 | 139 | /** Zero is not considered to be a positive value */ 140 | @inline def isPositive: Boolean = wei > zero.wei 141 | 142 | @inline def isZero: Boolean = wei == zero.wei 143 | 144 | @inline def toHex: String = s"0x${ wei.toString(16) }" 145 | 146 | override def toString: String = wei.bitLength match { 147 | case length if length <=3 => s"$wei Wei" 148 | case length if length <=6 => s"$asKWei KWei" 149 | case length if length <=9 => s"$asMWei MWei" 150 | case length if length <=12 => s"$asGWei GWei" 151 | case length if length <=15 => s"$asSzabo Szabo" 152 | case length if length <=18 => s"$asFinney Finney" 153 | case length if length <=21 => s"$asEther Ether" 154 | case length if length <=24 => s"$asKEther KEther" 155 | case length if length <=27 => s"$asMEther MEther" 156 | case _ => s"$asGEther GEther" 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/scala/com/micronautics/web3j/EthereumASynchronous.scala: -------------------------------------------------------------------------------- 1 | package com.micronautics.web3j 2 | 3 | import java.math.BigInteger 4 | import org.web3j.protocol.Web3j 5 | import org.web3j.protocol.core.DefaultBlockParameter 6 | import org.web3j.protocol.core.DefaultBlockParameterName.LATEST 7 | import org.web3j.protocol.core.methods.request 8 | import org.web3j.protocol.core.methods.response.{EthBlock, EthCompileSolidity, EthGetWork, EthLog, ShhMessages, Transaction, TransactionReceipt} 9 | import scala.collection.compat._ 10 | import scala.jdk.CollectionConverters._ 11 | import scala.compat.java8.OptionConverters._ 12 | import scala.collection.immutable.List 13 | import scala.compat.java8.FutureConverters._ 14 | import scala.concurrent.ExecutionContext.{global => defaultExecutionContext} 15 | import scala.concurrent.{ExecutionContext, Future} 16 | 17 | /** All of the methods in this class return a [[scala.concurrent.Future]] and do not block. 18 | * @param web3j can be shared with [[EthereumSynchronous]] 19 | * @param ec if no [[scala.concurrent.ExecutionContext]] is implicitly available, the default Scala 20 | * [[scala.concurrent.ExecutionContext]] is used. */ 21 | class EthereumASynchronous(val web3j: Web3j) 22 | (implicit val ec: ExecutionContext = defaultExecutionContext) { 23 | 24 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_accounts eth_accounts]] JSON-RPC endpoint. 25 | * @return the list of addresses owned by the client */ 26 | def accounts: Future[List[Address]] = 27 | web3j.ethAccounts.sendAsync.toScala.map(_.getAccounts.asScala.toList.map(Address)) 28 | 29 | /** Add the given identity address to the Whisper group. 30 | * 31 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_addtogroup shh_addtogroup]] JSON-RPC endpoint. 32 | * @return true if the identity was successfully added to the group */ 33 | def addToGroup(identityAddress: Address): Future[Boolean] = 34 | web3j.shhAddToGroup(identityAddress.value).sendAsync.toScala.map(_.addedToGroup) 35 | 36 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getbalance eth_getbalance]] JSON-RPC endpoint. 37 | * @param defaultBlockParameter either an integer block number, or the string "latest", "earliest" or "pending". 38 | * See the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#the-default-block-parameter specification]]. 39 | * @return the balance of the account of given address */ 40 | def balance(address: Address, defaultBlockParameter: DefaultBlockParameter): Future[Ether] = 41 | web3j.ethGetBalance(address.value, defaultBlockParameter).sendAsync.toScala.map(x => Ether(x.getBalance)) 42 | 43 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash eth_getblockbyhash]] JSON-RPC endpoint. 44 | * @return Option[EthBlock.Block] */ 45 | def blockByHash(blockHash: BlockHash, returnFullTransactionObjects: Boolean): Future[Option[EthBlock.Block]] = 46 | web3j.ethGetBlockByHash(blockHash.value, returnFullTransactionObjects).sendAsync.toScala.map(x => Option(x.getBlock)) 47 | 48 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash eth_getblockbyhash]] JSON-RPC endpoint. 49 | * @return Some(block object), or None if no block was found */ 50 | def blockByNumber( 51 | defaultBlockParameter: DefaultBlockParameter, 52 | returnFullTransactionObjects: Boolean = false 53 | ): Future[Option[EthBlock.Block]] = 54 | web3j 55 | .ethGetBlockByNumber(defaultBlockParameter, returnFullTransactionObjects) 56 | .sendAsync 57 | .toScala 58 | .map(x => Option(x.getBlock)) 59 | 60 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_blocknumber eth_blocknumber]] JSON-RPC endpoint. 61 | * @return the number of the most recent block */ 62 | def blockNumber: Future[BigInteger] = web3j.ethBlockNumber.sendAsync.toScala.map(_.getBlockNumber) 63 | 64 | def blockTransactionCountByHash(blockHash: String): Future[BigInteger] = 65 | web3j.ethGetBlockTransactionCountByHash(blockHash).sendAsync.toScala.map(_.getTransactionCount) 66 | 67 | def blockTransactionCountByNumber(defaultBlockParameter: DefaultBlockParameter): Future[BigInteger] = 68 | web3j.ethGetBlockTransactionCountByNumber(defaultBlockParameter).sendAsync.toScala.map(_.getTransactionCount) 69 | 70 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_call eth_call]] JSON-RPC endpoint. 71 | * @return value of executed contract, without creating a transaction on the block chain */ 72 | def call(transaction: request.Transaction, defaultBlockParameter: DefaultBlockParameter): Future[String] = 73 | web3j.ethCall(transaction, defaultBlockParameter).sendAsync.toScala.map(_.getValue) 74 | 75 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getcode eth_getcode]] JSON-RPC endpoint. 76 | * @return code at a given address */ 77 | def code(address: Address, defaultBlockParameter: DefaultBlockParameter): Future[String] = 78 | web3j.ethGetCode(address.value, defaultBlockParameter).sendAsync.toScala.map(_.getCode) 79 | 80 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_coinbase eth_coinbase]] JSON-RPC endpoint. 81 | * @return the client coinbase address */ 82 | def coinbaseAddress: Future[Address] = web3j.ethCoinbase.sendAsync.toScala.map(x => Address(x.getAddress)) 83 | 84 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_compilelll eth_compilelll]] JSON-RPC endpoint. 85 | * @return compiled LLL code */ 86 | def compileLLL(sourceCode: LLLSource): Future[LLLCompiled] = 87 | web3j.ethCompileLLL(sourceCode.value).sendAsync.toScala.map(x => LLLCompiled(x.getCompiledSourceCode)) 88 | 89 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_compileserpent eth_compileserpent]] JSON-RPC endpoint. 90 | * @return compiled Serpent code */ 91 | def compileSerpent(sourceCode: SerpentSource): Future[SerpentCompiled] = 92 | web3j.ethCompileSerpent(sourceCode.value).sendAsync.toScala.map(x => SerpentCompiled(x.getCompiledSourceCode)) 93 | 94 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_compilesolidity eth_compilesolidity]] JSON-RPC endpoint. 95 | * @return compiled Solidity code */ 96 | def compileSolidity(sourceCode: SoliditySource): Future[Map[String, EthCompileSolidity.Code]] = 97 | web3j.ethCompileSolidity(sourceCode.value).sendAsync.toScala.map(_.getCompiledSolidity.asScala.toMap) 98 | 99 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getcompilers eth_getcompilers]] JSON-RPC endpoint. 100 | * @return a list of available compilers found by the underlying Web3J library */ 101 | def compilers: Future[List[Compiler]] = 102 | web3j.ethGetCompilers.sendAsync.toScala.map(_.getCompilers.asScala.toList.map(Compiler)) 103 | 104 | /** Makes a call or transaction, which won't be added to the blockchain and returns the used gas, which can be used 105 | * for estimating the used gas. 106 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas eth_estimategas]] JSON-RPC endpoint. 107 | * @return amount of gas estimated */ 108 | def estimateGas(transaction: request.Transaction): Future[Ether] = 109 | web3j.ethEstimateGas(transaction).sendAsync.toScala.map(x => Ether(x.getAmountUsed)) 110 | 111 | /** Polling method for an eth filter. 112 | * 113 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterchanges eth_getfilterchanges]] JSON-RPC endpoint. 114 | * @return List of log items since last poll, could be Nil if nothing changed since the last poll */ 115 | def filterChangesEth(filterId: FilterId): Future[List[EthLog.LogResult[_]]] = 116 | web3j.ethGetFilterChanges(filterId.value).sendAsync.toScala.map(_.getLogs.asScala.toList) 117 | 118 | /** Polling method for a Whisper filter. 119 | * 120 | * Note: calling shh_getMessages will reset the buffer for this method to avoid duplicate messages. 121 | * 122 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_getfilterchanges shh_getfilterchanges]] JSON-RPC endpoint. 123 | * @return List of messages since the last poll; could be Nil if nothing changed since the last poll */ 124 | def filterChangesShh(filterId: FilterId): Future[List[ShhMessages.SshMessage]] = 125 | web3j.shhGetFilterChanges(filterId.value).sendAsync.toScala.map(_.getMessages.asScala.toList) 126 | 127 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gasprice eth_gasprice]] JSON-RPC endpoint. 128 | * @return the current price per gas in wei */ 129 | def gasPrice: Future[Ether] = web3j.ethGasPrice.sendAsync.toScala.map(x => Ether(x.getGasPrice)) 130 | 131 | /** Used for submitting mining hash rate 132 | * 133 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_submithashrate eth_submithashrate]] JSON-RPC endpoint. 134 | * @return true if submitting successfully */ 135 | def hashRate(hashRate: String, clientId: String): Future[Boolean] = 136 | web3j.ethSubmitHashrate(hashRate, clientId).sendAsync.toScala.map(_.submissionSuccessful) 137 | 138 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_hashrate eth_hashrate]] JSON-RPC endpoint. 139 | * @return the number of hashes per second that the node is mining at */ 140 | def hashRate: Future[BigInteger] = web3j.ethHashrate.sendAsync.toScala.map(_.getHashrate) 141 | 142 | /** Checks if the client hold the private keys for a given identity. 143 | * 144 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_hasidentity shh_hasidentity]] JSON-RPC endpoint. 145 | * @return returns true if this client holds the private key for that identity */ 146 | def hasIdentity(identityAddress: Address): Future[Boolean] = 147 | web3j.shhHasIdentity(identityAddress.value).sendAsync.toScala.map(_.hasPrivateKeyForIdentity) 148 | 149 | /** Retrieves binary data from the local database. 150 | * 151 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#db_gethex db_gethex]] JSON-RPC endpoint. 152 | * @return the retrieved value */ 153 | @deprecated("deprecated", "") 154 | def hexFrom(databaseName: String, keyName: String): Future[String] = 155 | web3j.dbGetHex(databaseName, keyName).sendAsync.toScala.map(_.getStoredValue) 156 | 157 | /** Stores binary data in the local database. 158 | * 159 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#db_puthex db_puthex]] JSON-RPC endpoint. 160 | * @return true if the value was stored */ 161 | @deprecated("deprecated", "") 162 | def hexTo(databaseName: String, keyName: String, dataToStore: String): Future[Boolean] = 163 | web3j.dbPutHex(databaseName, keyName, dataToStore).sendAsync.toScala.map(_.valueStored) 164 | 165 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#net_listening net_listening]] JSON-RPC endpoint. 166 | * @return true if this client is actively listening for network connections */ 167 | def isListening: Future[Boolean] = web3j.netListening.sendAsync.toScala.map(_.isListening) 168 | 169 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_mining eth_mining]] JSON-RPC endpoint. */ 170 | def isMining: Future[Boolean] = web3j.ethMining.sendAsync.toScala.map(_.isMining) 171 | 172 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_syncing eth_syncing]] JSON-RPC endpoint. */ 173 | def isSyncing: Future[Boolean] = web3j.ethSyncing.sendAsync.toScala.map(_.isSyncing) 174 | 175 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs eth_getlogs]] JSON-RPC endpoint. 176 | * @return List of all log items matching a given filter object */ 177 | def logs(ethFilter: request.EthFilter): Future[List[EthLog.LogResult[_]]] = 178 | web3j.ethGetLogs(ethFilter).sendAsync.toScala.map(_.getLogs.asScala.toList) 179 | 180 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterlogs eth_getfilterlogs]] JSON-RPC endpoint. 181 | * @return List of all log items with the matching filter id */ 182 | def logs(filterId: FilterId): Future[List[EthLog.LogResult[_]]] = 183 | web3j.ethGetFilterLogs(filterId.value).sendAsync.toScala.map(_.getLogs.asScala.toList) 184 | 185 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_getmessages shh_getmessages]] JSON-RPC endpoint. 186 | * @return all Whisper messages matching a filter */ 187 | def messages(filterId: FilterId): Future[List[ShhMessages.SshMessage]] = 188 | web3j.shhGetMessages(filterId.value).sendAsync.toScala.map(_.getMessages.asScala.toList) 189 | 190 | /** Creates a filter in the node, to notify when the state changes (logs). 191 | * To check if the state has changed, call `filterChanges`. 192 | * 193 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newblockfilter eth_newblockfilter]] JSON-RPC endpoint. 194 | * @return filter id */ 195 | def newBlockFilter: Future[FilterId] = web3j.ethNewBlockFilter.sendAsync.toScala.map(x => FilterId(x.getFilterId)) 196 | 197 | /** Get the next available nonce before creating a transaction */ 198 | // todo should a Nonce type be created? 199 | def nextNonce(address: Address): Future[Nonce] = nonce(address, LATEST) 200 | 201 | /** Creates a filter object, based on filter options, to notify when the state changes (logs). 202 | * To check if the state has changed, call `filterChanges`. 203 | * 204 | * Topics are order-dependent. 205 | * A transaction with a log with topics [A, B] will be matched by the following topic filters: 206 | * 207 | * - [] "anything" 208 | * - [A] "A in first position (and anything after)" 209 | * - [null, B] "anything in first position AND B in second position (and anything after)" 210 | * - [A, B] "A in first position AND B in second position (and anything after)" 211 | * - [ [A, B], [A, B] ] "(A OR B) in first position AND (A OR B) in second position (and anything after)" 212 | * 213 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter eth_newfilter]] JSON-RPC endpoint. 214 | * @return filter id */ 215 | def newFilter(ethFilter: request.EthFilter): Future[FilterId] = 216 | web3j.ethNewFilter(ethFilter).sendAsync.toScala.map(x => FilterId(x.getFilterId)) 217 | 218 | /** Create filter that notifies the client when whisper message is received that matches the filter options. 219 | * 220 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_newfilter shh_newfilter]] JSON-RPC endpoint. 221 | * @return The newly created filter as a BigInteger */ 222 | def newFilter(shhFilter: request.ShhFilter): Future[FilterId] = 223 | web3j.shhNewFilter(shhFilter).sendAsync.toScala.map(x => FilterId(x.getFilterId)) 224 | 225 | /** New Whisper group. 226 | * 227 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_newgroup shh_newgroup]] JSON-RPC endpoint. 228 | * @return address of the new group */ 229 | def newGroup: Future[Address] = web3j.shhNewGroup.sendAsync.toScala.map(x => Address(x.getAddress)) 230 | 231 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_newidentity shh_newidentity]] JSON-RPC endpoint. 232 | * @return address of the new whisper identity */ 233 | def newIdentity: Future[Address] = web3j.shhNewIdentity.sendAsync.toScala.map(x => Address(x.getAddress)) 234 | 235 | def newPendingTransactionFilter: Future[FilterId] = 236 | web3j.ethNewPendingTransactionFilter.sendAsync.toScala.map(x => FilterId(x.getFilterId)) 237 | 238 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactioncount eth_gettransactioncount]] JSON-RPC endpoint. 239 | * @see See [[https://github.com/ethereum/wiki/wiki/Glossary Glossary]] 240 | * @return the number of transactions sent from an address */ 241 | def nonce(address: Address, defaultBlockParameter: DefaultBlockParameter): Future[Nonce] = 242 | web3j.ethGetTransactionCount(address.value, defaultBlockParameter).sendAsync.toScala.map(x => Nonce(x.getTransactionCount)) 243 | 244 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#net_peercount net_peercount]] JSON-RPC endpoint. 245 | * @return number of peers currently connected to this client */ 246 | def peerCount: Future[BigInteger] = web3j.netPeerCount.sendAsync.toScala.map(_.getQuantity) 247 | 248 | /** Sends a whisper message. 249 | * 250 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_post shh_post]] JSON-RPC endpoint. 251 | * @return true if the message was sent */ 252 | def post(shhPost: request.ShhPost): Future[Boolean] = web3j.shhPost(shhPost).sendAsync.toScala.map(_.messageSent) 253 | 254 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendrawtransaction eth_sendrawtransaction]] JSON-RPC endpoint. 255 | * @return new message call transaction or a contract creation for signed transactions */ 256 | def sendRawTransaction(signedTransactionData: SignedData): Future[TransactionHash] = 257 | web3j.ethSendRawTransaction(signedTransactionData.value).sendAsync.toScala.map(x => TransactionHash(x.getTransactionHash)) 258 | 259 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction eth_sendtransaction]] JSON-RPC endpoint. 260 | * @return a new contract if the {{{Transaction.data}}} field contains code, else return a new transaction */ 261 | def sendTransaction(transaction: request.Transaction): Future[TransactionHash] = 262 | web3j.ethSendTransaction(transaction).sendAsync.toScala.map(x => TransactionHash(x.getTransactionHash)) 263 | 264 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#web3_sha3 web3_sha3]] JSON-RPC endpoint. 265 | * @param data the data to convert into an SHA3 hash 266 | * @return Keccak-256 hash (not the standardized SHA3-256 hash) of the given data */ 267 | def sha3(data: String): Future[Keccak256Hash] = web3j.web3Sha3(data).sendAsync.toScala.map(x => Keccak256Hash(x.getResult)) 268 | 269 | /** Calculates an Ethereum-specific signature with: 270 | * {{{sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))}}} 271 | * 272 | * By adding a prefix to the message makes the calculated signature recognisable as an Ethereum-specific signature. 273 | * This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim. 274 | * 275 | * Note: the address to sign with must be unlocked. 276 | * 277 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign eth_sign]] JSON-RPC endpoint. 278 | * @return Signature */ 279 | def sign(address: Address, sha3HashOfDataToSign: Keccak256Hash): Future[Signature] = 280 | web3j.ethSign(address.value, sha3HashOfDataToSign.value).sendAsync.toScala.map(x => Signature(x.getSignature)) 281 | 282 | /** Obtains a string from the local database. 283 | * 284 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#db_getstring db_getstring]] JSON-RPC endpoint. 285 | * @return previously stored value */ 286 | @deprecated("deprecated", "") 287 | def stringFrom(databaseName: String, keyName: String): Future[String] = 288 | web3j.dbGetString(databaseName, keyName).sendAsync.toScala.map(_.getStoredValue) 289 | 290 | /** Stores a string in the local database 291 | * 292 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#db_putstring db_putstring]] JSON-RPC endpoint. 293 | * @return true if the value was stored */ 294 | @deprecated("deprecated", "") 295 | def stringTo(databaseName: String, keyName: String, stringToStore: String): Future[Boolean] = 296 | web3j.dbPutString(databaseName, keyName, stringToStore).sendAsync.toScala.map(_.valueStored) 297 | 298 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getstorageat eth_getstorageat]] JSON-RPC endpoint. 299 | * @return the value from a storage position at a given address */ 300 | def storageAt(address: Address, position: BigInteger, defaultBlockParameter: DefaultBlockParameter): Future[String] = 301 | web3j.ethGetStorageAt(address.value, position, defaultBlockParameter).sendAsync.toScala.map(_.getData) 302 | 303 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyblockhashandindex eth_gettransactionbyblockhashandindex]] JSON-RPC endpoint. 304 | * @return Some containing transaction information by block hash and transaction index position, or None if no matching transaction was found */ 305 | def transactionByBlockHashAndIndex(blockHash: BlockHash, transactionIndex: BigInteger): Future[Option[Transaction]] = 306 | web3j.ethGetTransactionByBlockHashAndIndex(blockHash.value, transactionIndex).sendAsync.toScala.map(_.getTransaction.asScala) 307 | 308 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyblocknumberandindex eth_gettransactionbyblocknumberandindex]] JSON-RPC endpoint. 309 | * @return Some containing transaction information by block hash and transaction index position, or None if no matching transaction was found */ 310 | def transactionByBlockNumberAndIndex( 311 | defaultBlockParameter: DefaultBlockParameter, 312 | transactionIndex: BigInteger 313 | ): Future[Option[Transaction]] = 314 | web3j 315 | .ethGetTransactionByBlockNumberAndIndex(defaultBlockParameter, transactionIndex) 316 | .sendAsync 317 | .toScala 318 | .map(_.getTransaction.asScala) 319 | 320 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyhash eth_gettransactionbyhash]] JSON-RPC endpoint. 321 | * @return Future containing Some(transaction object), or None when no transaction was found */ 322 | def transactionByHash(transactionHash: TransactionHash): Future[Option[Transaction]] = 323 | web3j.ethGetTransactionByHash(transactionHash.value).sendAsync.toScala.map(_.getTransaction.asScala) 324 | 325 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt eth_gettransactionreceipt]] JSON-RPC endpoint. 326 | * @return the receipt of a transaction, identified by transaction hash. (Note: receipts are not available for pending transactions.) */ 327 | def transactionReceipt(transactionHash: TransactionHash): Future[Option[TransactionReceipt]] = 328 | web3j.ethGetTransactionReceipt(transactionHash.value).sendAsync.toScala.map(_.getTransactionReceipt.asScala) 329 | 330 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclecountbyblockhash eth_getunclecountbyblockhash]] JSON-RPC endpoint. 331 | * @return the number of uncles in a block from a block matching the given block hash */ 332 | def uncleCountByBlockHash(blockHash: BlockHash): Future[BigInteger] = 333 | web3j.ethGetUncleCountByBlockHash(blockHash.value).sendAsync.toScala.map(_.getUncleCount) 334 | 335 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclecountbyblocknumber eth_getunclecountbyblocknumber]] JSON-RPC endpoint. 336 | * @return the number of uncles in a block from a block matching the given block number */ 337 | def uncleCountByBlockNumber(defaultBlockParameter: DefaultBlockParameter): Future[BigInteger] = 338 | web3j.ethGetUncleCountByBlockNumber(defaultBlockParameter).sendAsync.toScala.map(_.getUncleCount) 339 | 340 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclebyblocknumberandindex eth_getunclebyblocknumberandindex]] JSON-RPC endpoint. 341 | * @return information about a uncle of a block by hash and uncle index position */ 342 | def uncleByBlockNumberAndIndex( 343 | defaultBlockParameter: DefaultBlockParameter, 344 | transactionIndex: BigInteger 345 | ): Future[EthBlock.Block] = 346 | web3j.ethGetUncleByBlockNumberAndIndex(defaultBlockParameter, transactionIndex).sendAsync.toScala.map(_.getBlock) 347 | 348 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclebyblockhashandindex eth_getunclebyblockhashandindex]] JSON-RPC endpoint. 349 | * @return information about a uncle of a block by hash and uncle index position */ 350 | def uncleByBlockHashAndIndex(blockHash: BlockHash, transactionIndex: BigInteger): Future[EthBlock.Block] = 351 | web3j.ethGetUncleByBlockHashAndIndex(blockHash.value, transactionIndex).sendAsync.toScala.map(_.getBlock) 352 | 353 | /** Uninstalls a filter with the given id. 354 | * Should always be called when watch is no longer needed. 355 | * 356 | * Note: Filters time out when they aren't requested with filterChanges for a period of time. 357 | * 358 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_uninstallfilter eth_uninstallfilter]] JSON-RPC endpoint. 359 | * @return true if the filter was successfully uninstalled */ 360 | def uninstallFilter(filterId: FilterId): Future[Boolean] = 361 | web3j.ethUninstallFilter(filterId.value).sendAsync.toScala.map(_.isUninstalled) 362 | 363 | /** Uninstalls a Whisper filter with the given id. 364 | * Should always be called when watch is no longer needed. 365 | * 366 | * Note: Filters time out when they aren't requested with filterChanges for a period of time. 367 | * 368 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_uninstallfilter shh_uninstallfilter]] JSON-RPC endpoint. 369 | * @return true if the filter was successfully uninstalled */ 370 | def uninstallShhFilter(filterId: FilterId): Future[Boolean] = 371 | web3j.shhUninstallFilter(filterId.value).sendAsync.toScala.map(_.isUninstalled) 372 | 373 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#web3_clientversion web3_clientversion]] JSON-RPC endpoint. 374 | * @return the Web3J client version used by this client */ 375 | def versionWeb3J: Future[String] = web3j.web3ClientVersion.sendAsync.toScala.map(_.getWeb3ClientVersion) 376 | 377 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#net_version net_version]] JSON-RPC endpoint. 378 | * @return the current network id */ 379 | def versionNet: Future[String] = web3j.netVersion.sendAsync.toScala.map(_.getNetVersion) 380 | 381 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_protocolversion eth_protocolversion]] JSON-RPC endpoint. 382 | * @return ethereum protocol version used by this client */ 383 | def versionProtocol: Future[String] = web3j.ethProtocolVersion.sendAsync.toScala.map(_.getProtocolVersion) 384 | 385 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_version shh_version]] JSON-RPC endpoint. 386 | * @return the current whisper protocol version. */ 387 | def versionShh: Future[String] = web3j.shhVersion.sendAsync.toScala.map(_.getVersion) 388 | 389 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getwork eth_getwork]] JSON-RPC endpoint. 390 | * @return the hash of the current block, the seedHash, and the boundary condition to be met ("target"). 391 | * The Array with the following properties: 392 | * 393 | * DATA, 32 Bytes - current block header pow-hash 394 | * DATA, 32 Bytes - the seed hash used for the DAG. 395 | * DATA, 32 Bytes - the boundary condition ("target"), 2^^256 / difficulty. */ 396 | def work: Future[EthGetWork] = web3j.ethGetWork.sendAsync.toScala 397 | 398 | /** Used for submitting a proof-of-work solution. 399 | * 400 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_submitwork eth_submitwork]] JSON-RPC endpoint. 401 | * @return true if the provided solution is valid */ 402 | // fixme What type of hash is headerPowHash? 403 | def work(nonce: Nonce, headerPowHash: Keccak256Hash, mixDigest: Digest): Future[Boolean] = 404 | web3j.ethSubmitWork(nonce.toString, headerPowHash.value, mixDigest.value).sendAsync.toScala.map(_.solutionValid) 405 | } 406 | -------------------------------------------------------------------------------- /src/main/scala/com/micronautics/web3j/EthereumSynchronous.scala: -------------------------------------------------------------------------------- 1 | package com.micronautics.web3j 2 | 3 | import java.math.BigInteger 4 | import org.web3j.protocol.Web3j 5 | import org.web3j.protocol.core.DefaultBlockParameter 6 | import org.web3j.protocol.core.DefaultBlockParameterName.LATEST 7 | import org.web3j.protocol.core.methods.request 8 | import org.web3j.protocol.core.methods.request.ShhFilter 9 | import org.web3j.protocol.core.methods.response.{EthBlock, EthCompileSolidity, EthGetWork, EthLog, ShhMessages, Transaction, TransactionReceipt} 10 | import scala.collection.compat._ 11 | import scala.jdk.CollectionConverters._ 12 | import scala.compat.java8.OptionConverters._ 13 | import scala.collection.immutable.List 14 | 15 | /** All of the methods in this class block until a value is ready to be returned to the caller. 16 | * @param web3j can be shared with [[EthereumASynchronous]] */ 17 | class EthereumSynchronous(val web3j: Web3j) { 18 | 19 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_accounts eth_accounts]] JSON-RPC endpoint. 20 | * @return the list of addresses owned by the client */ 21 | def accounts: List[Address] = web3j.ethAccounts.send.getAccounts.asScala.toList.map(Address) 22 | 23 | /** Add the given identity address to the Whisper group. 24 | * 25 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_addtogroup shh_addtogroup]] JSON-RPC endpoint. 26 | * @return true if the identity was successfully added to the group */ 27 | def addToGroup(identityAddress: Address): Boolean = web3j.shhAddToGroup(identityAddress.value).send.addedToGroup 28 | 29 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getbalance eth_getbalance]] JSON-RPC endpoint. 30 | * @param defaultBlockParameter either an integer block number, or the string "latest", "earliest" or "pending". 31 | * See the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#the-default-block-parameter specification]]. 32 | * @return the balance of the account at given address */ 33 | def balance(address: Address, defaultBlockParameter: DefaultBlockParameter): Ether = 34 | Ether(web3j.ethGetBalance(address.value, defaultBlockParameter).send.getBalance) 35 | 36 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbyhash eth_getblockbyhash]] JSON-RPC endpoint. 37 | * @return Some(block object), or None if no block was found */ 38 | def blockByHash(blockHash: BlockHash, returnFullTransactionObjects: Boolean): Option[EthBlock.Block] = 39 | Option(web3j.ethGetBlockByHash(blockHash.value, returnFullTransactionObjects).send.getBlock) 40 | 41 | def blockByNumber( 42 | defaultBlockParameter: DefaultBlockParameter, 43 | returnFullTransactionObjects: Boolean = false 44 | ): Option[EthBlock.Block] = 45 | Option(web3j.ethGetBlockByNumber(defaultBlockParameter, returnFullTransactionObjects).send.getBlock) 46 | 47 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_blocknumber eth_blocknumber]] JSON-RPC endpoint. 48 | * @return the number of the most recent block */ 49 | // todo define a type for BlockNumber? 50 | def blockNumber: BigInteger = web3j.ethBlockNumber.send.getBlockNumber 51 | 52 | def blockTransactionCountByHash(blockHash: BlockHash): BigInteger = 53 | web3j.ethGetBlockTransactionCountByHash(blockHash.value).send.getTransactionCount 54 | 55 | def blockTransactionCountByNumber(defaultBlockParameter: DefaultBlockParameter): BigInteger = 56 | web3j.ethGetBlockTransactionCountByNumber(defaultBlockParameter).send.getTransactionCount 57 | 58 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_call eth_call]] JSON-RPC endpoint. 59 | * @return value of executed contract, without creating a transaction on the block chain */ 60 | def call(transaction: request.Transaction, defaultBlockParameter: DefaultBlockParameter): String = 61 | web3j.ethCall(transaction, defaultBlockParameter).send.getValue 62 | 63 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getcode eth_getcode]] JSON-RPC endpoint. 64 | * @return code at a given address */ 65 | def code(address: Address, defaultBlockParameter: DefaultBlockParameter): String = 66 | web3j.ethGetCode(address.value, defaultBlockParameter).send.getCode 67 | 68 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_coinbase eth_coinbase]] JSON-RPC endpoint. 69 | * @return the client coinbase address */ 70 | def coinbaseAddress: Address = Address(web3j.ethCoinbase.send.getAddress) 71 | 72 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_compilelll eth_compilelll]] JSON-RPC endpoint. 73 | * @return compiled LLL code */ 74 | def compileLLL(sourceCode: LLLSource): LLLCompiled = 75 | LLLCompiled(web3j.ethCompileLLL(sourceCode.value).send.getCompiledSourceCode) 76 | 77 | def compileSerpent(sourceCode: SerpentSource): SerpentCompiled = 78 | SerpentCompiled(web3j.ethCompileSerpent(sourceCode.value).send.getCompiledSourceCode) 79 | 80 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_compilesolidity eth_compilesolidity]] JSON-RPC endpoint. 81 | * @return compiled Solidity code */ 82 | def compileSolidity(sourceCode: SoliditySource): Map[String, EthCompileSolidity.Code] = 83 | web3j.ethCompileSolidity(sourceCode.value).send.getCompiledSolidity.asScala.toMap 84 | 85 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getcompilers eth_getcompilers]] JSON-RPC endpoint. 86 | * @return a list of available compilers found by the underlying Web3J library */ 87 | def compilers: List[Compiler] = web3j.ethGetCompilers.send.getCompilers.asScala.toList.map(Compiler) 88 | 89 | /** Makes a call or transaction, which won't be added to the blockchain and returns the used gas, which can be used 90 | * for estimating the used gas. 91 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_estimategas eth_estimategas]] JSON-RPC endpoint. 92 | * @return amount of gas estimated */ 93 | def estimateGas(transaction: request.Transaction): Ether = Ether(web3j.ethEstimateGas(transaction).send.getAmountUsed) 94 | 95 | /** Polling method for an eth filter. 96 | * 97 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterchanges eth_getfilterchanges]] JSON-RPC endpoint. 98 | * @return List of log items since last poll, could be an empty array if nothing has changed since last poll */ 99 | def filterChangesEth(filterId: FilterId): List[EthLog.LogResult[_]] = 100 | web3j.ethGetFilterChanges(filterId.value).send.getLogs.asScala.toList 101 | 102 | /** Polling method for a Whisper filter. 103 | * 104 | * Note: calling shh_getMessages will reset the buffer for this method to avoid duplicate messages. 105 | * 106 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_getfilterchanges shh_getfilterchanges]] JSON-RPC endpoint. 107 | * @return List of messages since the last poll; could be Nil if nothing changed since the last poll */ 108 | def filterChangesShh(filterId: FilterId): List[ShhMessages.SshMessage] = 109 | web3j.shhGetFilterChanges(filterId.value).send.getMessages.asScala.toList 110 | 111 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gasprice eth_gasprice]] JSON-RPC endpoint. 112 | * @return the current price per gas in wei */ 113 | def gasPrice: Ether = Ether(web3j.ethGasPrice.send.getGasPrice) 114 | 115 | /** Query the hash rate. 116 | * 117 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_hashrate eth_hashrate]] JSON-RPC endpoint. 118 | * @return number of hashes per second that the node is mining at */ 119 | def hashRate: BigInteger = web3j.ethHashrate.send.getHashrate 120 | 121 | /** Used for submitting mining hash rate 122 | * 123 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_submithashrate eth_submithashrate]] JSON-RPC endpoint. 124 | * @return true if submitting successfully */ 125 | def hashRate(hashRate: String, clientId: String): Boolean = 126 | web3j.ethSubmitHashrate(hashRate, clientId).send.submissionSuccessful 127 | 128 | /** Checks if the client hold the private keys for a given identity. 129 | * 130 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_hasidentity shh_hasidentity]] JSON-RPC endpoint. 131 | * @return returns true if this client holds the private key for that identity */ 132 | def hasIdentity(identityAddress: Address): Boolean = 133 | web3j.shhHasIdentity(identityAddress.value).send.hasPrivateKeyForIdentity 134 | 135 | /** Retrieves binary data from the local database. 136 | * 137 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#db_gethex db_gethex]] JSON-RPC endpoint. 138 | * @return the retrieved value */ 139 | @deprecated("deprecated", "") 140 | def hexFrom(databaseName: String, keyName: String): String = 141 | web3j.dbGetHex(databaseName, keyName).send.getStoredValue 142 | 143 | /** Stores binary data in the local database. 144 | * 145 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#db_puthex db_puthex]] JSON-RPC endpoint. 146 | * @return true if the value was stored */ 147 | @deprecated("deprecated", "") 148 | def hexTo(databaseName: String, keyName: String, dataToStore: String): Boolean = 149 | web3j.dbPutHex(databaseName, keyName, dataToStore).send.valueStored 150 | 151 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#net_listening net_listening]] JSON-RPC endpoint. 152 | * @return true if this client is actively listening for network connections */ 153 | def isListening: Boolean = web3j.netListening.send.isListening 154 | 155 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_mining eth_mining]] JSON-RPC endpoint. */ 156 | def isMining: Boolean = web3j.ethMining.send.isMining 157 | 158 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_syncing eth_syncing]] JSON-RPC endpoint. */ 159 | def isSyncing: Boolean = web3j.ethSyncing.send.isSyncing 160 | 161 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs eth_getlogs]] JSON-RPC endpoint. 162 | * @return List of all log items matching a given filter object */ 163 | def logs(ethFilter: request.EthFilter): List[EthLog.LogResult[_]] = 164 | web3j.ethGetLogs(ethFilter).send.getLogs.asScala.toList 165 | 166 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getfilterlogs eth_getfilterlogs]] JSON-RPC endpoint. 167 | * @return List of all log items with the matching filter id */ 168 | def logs(filterId: FilterId): List[EthLog.LogResult[_]] = 169 | web3j.ethGetFilterLogs(filterId.value).send.getLogs.asScala.toList 170 | 171 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_getmessages shh_getmessages]] JSON-RPC endpoint. 172 | * @return all Whisper messages matching a filter */ 173 | def messages(filterId: FilterId): List[ShhMessages.SshMessage] = 174 | web3j.shhGetMessages(filterId.value).send.getMessages.asScala.toList 175 | 176 | /** Creates a filter in the node, to notify when the state changes (logs). 177 | * To check if the state has changed, call `filterChanges`. 178 | * 179 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newblockfilter eth_newblockfilter]] JSON-RPC endpoint. 180 | * @return filter id */ 181 | def newBlockFilter: FilterId = FilterId(web3j.ethNewBlockFilter.send.getFilterId) 182 | 183 | /** Creates a filter object, based on filter options, to notify when the state changes (logs). 184 | * To check if the state has changed, call `filterChanges`. 185 | * 186 | * Topics are order-dependent. 187 | * A transaction with a log with topics [A, B] will be matched by the following topic filters: 188 | * 189 | * - [] "anything" 190 | * - [A] "A in first position (and anything after)" 191 | * - [null, B] "anything in first position AND B in second position (and anything after)" 192 | * - [A, B] "A in first position AND B in second position (and anything after)" 193 | * - [ [A, B], [A, B] ] "(A OR B) in first position AND (A OR B) in second position (and anything after)" 194 | * 195 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_newfilter eth_newfilter]] JSON-RPC endpoint. 196 | * @return filter id */ 197 | def newFilter(ethFilter: request.EthFilter): FilterId = FilterId(web3j.ethNewFilter(ethFilter).send.getFilterId) 198 | 199 | /** Create filter that notifies the client when whisper message is received that matches the filter options. 200 | * 201 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_newfilter shh_newfilter]] JSON-RPC endpoint. 202 | * @return The newly created filter as a BigInteger */ 203 | def newFilter(shhFilter: ShhFilter): FilterId = FilterId(web3j.shhNewFilter(shhFilter).send.getFilterId) 204 | 205 | /** New Whisper group. 206 | * 207 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_newgroup shh_newgroup]] JSON-RPC endpoint. 208 | * @return address of the new group */ 209 | def newGroup: Address = Address(web3j.shhNewGroup.send.getAddress) 210 | 211 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_newidentity shh_newidentity]] JSON-RPC endpoint. 212 | * @return address of the new whisper identity */ 213 | def newIdentity: Address = Address(web3j.shhNewIdentity.send.getAddress) 214 | 215 | def newPendingTransactionFilter: FilterId = FilterId(web3j.ethNewPendingTransactionFilter.send.getFilterId) 216 | 217 | /** Get the next available nonce before creating a transaction */ 218 | def nextNonce(address: Address): Nonce = nonce(address, LATEST) 219 | 220 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactioncount eth_gettransactioncount]] JSON-RPC endpoint. 221 | * @see See [[https://github.com/ethereum/wiki/wiki/Glossary Glossary]] 222 | * @return the number of transactions sent from an address */ 223 | def nonce(address: Address, defaultBlockParameter: DefaultBlockParameter): Nonce = 224 | Nonce(web3j.ethGetTransactionCount(address.value, defaultBlockParameter).send.getTransactionCount) 225 | 226 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#net_peercount net_peercount]] JSON-RPC endpoint. 227 | * @return number of peers currently connected to this client */ 228 | def peerCount: BigInteger = web3j.netPeerCount.send.getQuantity 229 | 230 | /** Sends a whisper message. 231 | * 232 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_post shh_post]] JSON-RPC endpoint. 233 | * @return true if the message was sent */ 234 | def post(shhPost: request.ShhPost): Boolean = web3j.shhPost(shhPost).send.messageSent 235 | 236 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendrawtransaction eth_sendrawtransaction]] JSON-RPC endpoint. 237 | * @return new message call transaction or a contract creation for signed transactions */ 238 | def sendRawTransaction(signedTransactionData: SignedData): TransactionHash= 239 | TransactionHash(web3j.ethSendRawTransaction(signedTransactionData.value).send.getTransactionHash) 240 | 241 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction eth_sendtransaction]] JSON-RPC endpoint. 242 | * @return a new contract if the {{{Transaction.data}}} field contains code, else return a new transaction */ 243 | def sendTransaction(transaction: request.Transaction): TransactionHash = 244 | TransactionHash(web3j.ethSendTransaction(transaction).send.getTransactionHash) 245 | 246 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#web3_sha3 web3_sha3]] JSON-RPC endpoint. 247 | * @param data the data to convert into an SHA3 hash 248 | * @return Keccak-256 hash (not the standardized SHA3-256 hash) of the given data */ 249 | def sha3(data: String): Keccak256Hash = Keccak256Hash(web3j.web3Sha3(data).send.getResult) 250 | 251 | /** Calculates an Ethereum-specific signature with: 252 | * {{{sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))}}} 253 | * 254 | * By adding a prefix to the message makes the calculated signature recognisable as an Ethereum-specific signature. 255 | * This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim. 256 | * 257 | * Note: the address to sign with must be unlocked. 258 | * 259 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign eth_sign]] JSON-RPC endpoint. 260 | * @return Signature */ 261 | def sign(address: Address, sha3HashOfDataToSign: String): Signature = 262 | Signature(web3j.ethSign(address.value, sha3HashOfDataToSign).send.getSignature) 263 | 264 | /** Obtains a string from the local database. 265 | * 266 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#db_getstring db_getstring]] JSON-RPC endpoint. 267 | * @return previously stored value */ 268 | @deprecated("deprecated", "") 269 | def stringFrom(databaseName: String, keyName: String): String = 270 | web3j.dbGetString(databaseName, keyName).send.getStoredValue 271 | 272 | /** Stores a string in the local database 273 | * 274 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#db_putstring db_putstring]] JSON-RPC endpoint. 275 | * @return true if the value was stored */ 276 | @deprecated("deprecated", "") 277 | def stringTo(databaseName: String, keyName: String, stringToStore: String): Boolean = 278 | web3j.dbPutString(databaseName, keyName, stringToStore).send.valueStored 279 | 280 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getstorageat eth_getstorageat]] JSON-RPC endpoint. 281 | * @return the value from a storage position at a given address */ 282 | def storageAt(address: Address, position: BigInteger, defaultBlockParameter: DefaultBlockParameter): String = 283 | web3j.ethGetStorageAt(address.value, position, defaultBlockParameter).send.getData 284 | 285 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyblockhashandindex eth_gettransactionbyblockhashandindex]] JSON-RPC endpoint. 286 | * @return Some containing transaction information by block hash and transaction index position, or None if no matching transaction was found */ 287 | def transactionByBlockHashAndIndex(blockHash: BlockHash, transactionIndex: BigInteger): Option[Transaction] = 288 | web3j.ethGetTransactionByBlockHashAndIndex(blockHash.value, transactionIndex).send.getTransaction.asScala 289 | 290 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyblocknumberandindex eth_gettransactionbyblocknumberandindex]] JSON-RPC endpoint. 291 | * @return Some containing transaction information by block hash and transaction index position, or None if no matching transaction was found */ 292 | def transactionByBlockNumberAndIndex( 293 | defaultBlockParameter: DefaultBlockParameter, 294 | transactionIndex: BigInteger 295 | ): Option[Transaction] = 296 | web3j.ethGetTransactionByBlockNumberAndIndex(defaultBlockParameter, transactionIndex).send.getTransaction.asScala 297 | 298 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionbyhash eth_gettransactionbyhash]] JSON-RPC endpoint. 299 | * @return Future containing Some(transaction object), or None when no transaction was found */ 300 | def transactionByHash(transactionHash: TransactionHash): Option[Transaction] = 301 | web3j.ethGetTransactionByHash(transactionHash.value).send.getTransaction.asScala 302 | 303 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt eth_gettransactionreceipt]] JSON-RPC endpoint. 304 | * @return the receipt of a transaction, identified by transaction hash. (Note: receipts are not available for pending transactions.) */ 305 | def transactionReceipt(transactionHash: TransactionHash): Option[TransactionReceipt] = 306 | web3j.ethGetTransactionReceipt(transactionHash.value).send.getTransactionReceipt.asScala 307 | 308 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclebyblocknumberandindex eth_getunclebyblocknumberandindex]] JSON-RPC endpoint. 309 | * @return information about a uncle of a block by hash and uncle index position */ 310 | def uncleByBlockNumberAndIndex(defaultBlockParameter: DefaultBlockParameter, transactionIndex: BigInteger): EthBlock.Block = 311 | web3j.ethGetUncleByBlockNumberAndIndex(defaultBlockParameter, transactionIndex).send.getBlock 312 | 313 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclebyblockhashandindex eth_getunclebyblockhashandindex]] JSON-RPC endpoint. 314 | * @return information about a uncle of a block by hash and uncle index position */ 315 | def uncleByBlockHashAndIndex(blockHash: BlockHash, transactionIndex: BigInteger): EthBlock.Block = 316 | web3j.ethGetUncleByBlockHashAndIndex(blockHash.value, transactionIndex).send.getBlock 317 | 318 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclecountbyblockhash eth_getunclecountbyblockhash]] JSON-RPC endpoint. 319 | * @return the number of uncles in a block from a block matching the given block hash */ 320 | def uncleCountByBlockHash(blockHash: BlockHash): BigInteger = 321 | web3j.ethGetUncleCountByBlockHash(blockHash.value).send.getUncleCount 322 | 323 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getunclecountbyblocknumber eth_getunclecountbyblocknumber]] JSON-RPC endpoint. 324 | * @return the number of uncles in a block from a block matching the given block number */ 325 | def uncleCountByBlockNumber(defaultBlockParameter: DefaultBlockParameter): BigInteger = 326 | web3j.ethGetUncleCountByBlockNumber(defaultBlockParameter).send.getUncleCount 327 | 328 | /** Uninstalls a filter with given id. 329 | * Should always be called when watch is no longer needed. 330 | * 331 | * Note: Filters time out when they aren't requested with filterChanges for a period of time. 332 | * 333 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_uninstallfilter eth_uninstallfilter]] JSON-RPC endpoint. 334 | * @return true if the filter was successfully uninstalled */ 335 | def uninstallFilter(filterId: FilterId): Boolean = 336 | web3j.ethUninstallFilter(filterId.value).send.isUninstalled 337 | 338 | /** Uninstalls a Whisper filter with the given id. 339 | * Should always be called when watch is no longer needed. 340 | * 341 | * Note: Filters time out when they aren't requested with filterChanges for a period of time. 342 | * 343 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_uninstallfilter shh_uninstallfilter]] JSON-RPC endpoint. 344 | * @return true if the filter was successfully uninstalled */ 345 | def uninstallShhFilter(filterId: FilterId): Boolean = 346 | web3j.shhUninstallFilter(filterId.value).send.isUninstalled 347 | 348 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#web3_clientversion web3_clientversion]] JSON-RPC endpoint. 349 | * @return the Web3J client version used by this client */ 350 | def versionWeb3J: String = web3j.web3ClientVersion.send.getWeb3ClientVersion 351 | 352 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#net_version net_version]] JSON-RPC endpoint. 353 | * @return the current network id */ 354 | def versionNet: String = web3j.netVersion.send.getNetVersion 355 | 356 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_protocolversion eth_protocolversion]] JSON-RPC endpoint. 357 | * @return ethereum protocol version used by this client */ 358 | def versionProtocol: String = web3j.ethProtocolVersion.send.getProtocolVersion 359 | 360 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#shh_version shh_version]] JSON-RPC endpoint. 361 | * @return the current whisper protocol version. */ 362 | def versionShh: String = web3j.shhVersion.send.getVersion 363 | 364 | /** Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getwork eth_getwork]] JSON-RPC endpoint. 365 | * @return the hash of the current block, the seedHash, and the boundary condition to be met ("target"). 366 | * The Array with the following properties: 367 | * 368 | * DATA, 32 Bytes - current block header pow-hash 369 | * DATA, 32 Bytes - the seed hash used for the DAG. 370 | * DATA, 32 Bytes - the boundary condition ("target"), 2^^256 / difficulty. */ 371 | def work: EthGetWork = web3j.ethGetWork.send 372 | 373 | /** Used for submitting a proof-of-work solution. 374 | * 375 | * Invokes the [[https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_submitwork eth_submitwork]] JSON-RPC endpoint. 376 | * @return true if the provided solution is valid */ 377 | // todo what type of Hash should headerPowHash be? 378 | def work(nonce: Nonce, headerPowHash: Keccak256Hash, mixDigest: Digest): Boolean = 379 | web3j.ethSubmitWork(nonce.toString, headerPowHash.value, mixDigest.value).send.solutionValid 380 | } 381 | -------------------------------------------------------------------------------- /src/main/scala/com/micronautics/web3j/InfuraNetwork.java: -------------------------------------------------------------------------------- 1 | package com.micronautics.web3j; 2 | 3 | /** From the [[https://docs.web3j.io/transactions.html#ethereum-testnets web3j testnet docs]]: 4 | * For development, its recommended you use the Rinkeby (geth only) or Kovan (Parity only) test networks. 5 | * This is because they use a Proof of Authority (PoA) consensus mechanism, 6 | * ensuring transactions and blocks are created in a consistent and timely manner. 7 | * The Ropsten testnet, although closest to the Mainnet as it uses Proof of Work (PoW) consensus, 8 | * has been subject to attacks in the past and tends to be more problematic for developers. */ 9 | public enum InfuraNetwork { 10 | MAINNET, KOVAN, RINKEBY, ROPSTEN 11 | } 12 | -------------------------------------------------------------------------------- /src/main/scala/com/micronautics/web3j/ValueClasses.scala: -------------------------------------------------------------------------------- 1 | package com.micronautics.web3j 2 | 3 | import java.math.BigInteger 4 | import org.web3j.protocol.core.methods.response.EthCompileSolidity 5 | 6 | case class Address(value: String) extends AnyVal { 7 | @inline override def toString: String = value.toString 8 | } 9 | 10 | case class Compiler(value: String) extends AnyVal { 11 | @inline override def toString: String = value.toString 12 | } 13 | 14 | case class Digest(value: String) extends AnyVal { 15 | @inline override def toString: String = value.toString 16 | } 17 | 18 | // @see See [[https://github.com/ethereum/wiki/wiki/Ethash Ethash]] for proof of work 19 | case class EtHash(value: String) extends AnyVal { 20 | @inline override def toString: String = value.toString 21 | } 22 | 23 | case class BlockHash(value: String) extends AnyVal { 24 | @inline override def toString: String = value.toString 25 | } 26 | 27 | case class FilterId(value: BigInteger) extends AnyVal { 28 | @inline override def toString: String = value.toString 29 | } 30 | 31 | case class LLLCompiled(value: String) extends AnyVal { 32 | @inline override def toString: String = value.toString 33 | } 34 | 35 | case class LLLSource(value: String) extends AnyVal { 36 | @inline override def toString: String = value.toString 37 | } 38 | 39 | /** An account nonce is a transaction counter, provided by Ethereum for each Account. 40 | * Nonces prevent replay attacks wherein a transaction sending Ether from A to B can be replayed by B over and over to 41 | * continually drain A's balance. 42 | * @see See [[https://github.com/ethereum/wiki/wiki/Glossary Glossary]] */ 43 | case class Nonce(value: BigInt) extends AnyVal { 44 | @inline def bigInteger: BigInteger = value.bigInteger 45 | 46 | @inline override def toString: String = value.toString 47 | } 48 | 49 | case class SerpentCompiled(value: String) extends AnyVal { 50 | @inline override def toString: String = value.toString 51 | } 52 | 53 | case class SerpentSource(value: String) extends AnyVal { 54 | @inline override def toString: String = value.toString 55 | } 56 | 57 | /** The SHA3 hash is more properly referred to as 58 | * [[https://ethereum.stackexchange.com/questions/550/which-cryptographic-hash-function-does-ethereum-use Keccak-256]] */ 59 | // todo better to use value classes to indicate functionality, not how something was created. Delete this type and replace by one of the others, or rename this 60 | case class Keccak256Hash(value: String) extends AnyVal { 61 | @inline override def toString: String = value.toString 62 | } 63 | 64 | case class Signature(value: String) extends AnyVal { 65 | @inline override def toString: String = value.toString 66 | } 67 | 68 | case class SignedData(value: String) extends AnyVal { 69 | @inline override def toString: String = value.toString 70 | } 71 | 72 | /** Web3J already has [[EthCompileSolidity.Code]] to represent Solidity compiled code */ 73 | case class SoliditySource(value: String) extends AnyVal { 74 | @inline override def toString: String = value.toString 75 | } 76 | 77 | case class TransactionHash(value: String) extends AnyVal { 78 | @inline override def toString: String = value.toString 79 | } 80 | -------------------------------------------------------------------------------- /src/main/scala/com/micronautics/web3j/Web3JScala.scala: -------------------------------------------------------------------------------- 1 | package com.micronautics.web3j 2 | 3 | import com.micronautics.web3j.InfuraNetwork._ 4 | import org.web3j.protocol.Web3j 5 | import org.web3j.protocol.http.HttpService 6 | import org.web3j.protocol.infura.InfuraHttpService 7 | import io.reactivex.{Flowable, Observable} 8 | import scala.concurrent.ExecutionContext 9 | 10 | /** [[https://www.web3j.io Web3J]] builders and stateless methods. */ 11 | object Web3JScala { 12 | lazy val cmd: Cmd = new Cmd 13 | 14 | /** @see See [[https://docs.web3j.io/management_apis.html?highlight=httpservice Management APIs]] */ 15 | def fromHttp(url: String = "http://localhost:8545"): Web3j = { 16 | val web3j = Web3j.build(new HttpService(url)) 17 | verifyConnection(web3j) 18 | web3j 19 | } 20 | 21 | /** @see See [[http://www.ziggify.com/blog/blockchain-stack-1-installing-ethereum-geth-smart-contract/ Installing Ethereum Geth and your first smart contract]] 22 | * @see See the [[http://faucet.ropsten.be:3001/ Ethereum Ropsten Faucet]] 23 | * @see See [[https://docs.web3j.io/infura.html Using Infura with web3j]] 24 | * @param network defaults to the Ropsten test network */ 25 | def fromInfura(token: String, network: InfuraNetwork = ROPSTEN): Web3j = { 26 | val web3j = Web3j.build(new InfuraHttpService(s"https://${ network.name }.infura.io/$token")) 27 | verifyConnection(web3j) 28 | web3j 29 | } 30 | 31 | /** Invokes fn on all elements observed from the given Observable[T] */ 32 | def observe[T](observable: Observable[T]) 33 | (fn: T => Unit): Unit = 34 | observable.subscribe(fn(_)) 35 | 36 | /** Only runs fn on the first n elements observed from the given Observable[T] */ 37 | def observe[T](n: Int) 38 | (observable: Flowable[T]) 39 | (fn: T => Unit): Unit = 40 | observable.limit(n.toLong).doOnEach { t => 41 | fn(t.getValue) 42 | } 43 | 44 | /** Compile the smart contract. 45 | * Note that `solc` generates [[https://en.wikipedia.org/wiki/Camel_case camelCase]] names from 46 | * [[https://en.wikipedia.org/wiki/Snake_case snake_case]] names. 47 | * {{{solc --bin --abi --optimize --overwrite -o abi/ src/test/resources/basic_info_getter.sol}}} */ 48 | def solc(solCFileName: String, outputDirectory: String="abi/"): String = cmd.getOutputFrom( 49 | "solc", 50 | "--bin", 51 | "--abi", 52 | "--optimize", 53 | "--overwrite", 54 | "-o", outputDirectory, 55 | solCFileName 56 | ) 57 | 58 | /** Verify web3j is connected to a JSON-RPC endpoint */ 59 | def verifyConnection(web3j: Web3j): Boolean = try { 60 | web3j.web3ClientVersion.send.getWeb3ClientVersion 61 | true 62 | } catch { 63 | case e: Exception => 64 | println(s"${ e.getMessage }. Is geth or eth running?") 65 | System.exit(0) 66 | false 67 | } 68 | 69 | /** Generate the wrapper code from the compiled smart contract using web3j’s command-line tools 70 | * The `bin` and `abi` files are both read from the same directory, specified by `-o`. 71 | * {{{bin/web3j solidity generate abi/basic_info_getter.bin abi/basic_info_getter.abi -o abiWrapper/ -p com.micronautics.solidity}}} */ 72 | def wrapAbi( 73 | filename: String, 74 | packageName: String = "com.micronautics.solidity", 75 | inputDirectory: String = "abi/", 76 | outputDirectory: String = "abiWrapper/" 77 | ): String = cmd.getOutputFrom( 78 | "bin/web3j", "solidity", 79 | "generate", s"$inputDirectory/${ toCamelCase(filename) }.bin", s"$inputDirectory/${ toCamelCase(filename) }.abi", 80 | "-o", outputDirectory, 81 | "-p", packageName 82 | ) 83 | 84 | protected def toCamelCase(s: String): String = { 85 | val words = s.split("_") 86 | val tail = words.tail.map { word => word.head.toUpper.toString + word.tail } 87 | words.head + tail.mkString 88 | } 89 | } 90 | 91 | /** Wrapper for Web3J */ 92 | class Web3JScala(val web3j: Web3j) 93 | (implicit ec: ExecutionContext) { 94 | lazy val async = new EthereumASynchronous(web3j) 95 | lazy val sync = new EthereumSynchronous(web3j) 96 | } 97 | -------------------------------------------------------------------------------- /src/main/scala/com/micronautics/web3j/package.scala: -------------------------------------------------------------------------------- 1 | package com.micronautics 2 | 3 | import org.web3j.protocol.core.methods.response 4 | 5 | /** 6 | * This project is an idiomatic Scala wrapper around [[https://www.web3j.io Web3J]] for Ethereum. 7 | * This project is built with Scala 2.12, and requires the Java 8 runtime; it is not yet compatible with Java 9. 8 | * 9 | * This project promotes idiomatic Scala in the following ways: 10 | * - Variables and no-argument methods are actually names of properties, so `set` and `get` prefixes are not used. 11 | * This means some properties do not have exactly the same name as their Web3J counterpart. 12 | * - Zero-argument methods only require parentheses if they perform side effects. 13 | * - Scala data types are used to the maximum extent that makes sense. 14 | * For example, [[scala.concurrent.Future]]. 15 | * - A functional programming style is encouraged by always returning immutable data types from methods. 16 | * For example, [[scala.collection.immutable.List]] 17 | * 18 | * The [[https://github.com/ethereum/wiki/wiki/JSON-RPC Ethereum JSON-RPC documentation]] 19 | * was the source of many the comments incorporated into this Scaladoc. 20 | * 21 | * The JSON-RPC [[https://github.com/ethereum/wiki/wiki/JSON-RPC#the-default-block-parameter default block parameter]] 22 | * can represent a `QUANTITY` or a `TAG`. 23 | * Quantities are expressed as integer block numbers, and tags are strings with one of the values "latest", "earliest" or "pending". 24 | * The [[https://jar-download.com/javaDoc/org.web3j/core/3.0.2/index.html?org/web3j/protocol/core/DefaultBlockParameter.html Java implementation]] 25 | * performs the same function as the underlying JSON-RPC implementation. 26 | * 27 | * [[https://github.com/ethereum/wiki/wiki/Whisper Whisper]] 28 | * is an experimental communication protocol of the Ethereum P2P protocol suite that allows 29 | * for messaging between users' DApps (Ethereum Distributed Applications). 30 | * Whisper uses the same network that the blockchain runs on. 31 | * The protocol is separate from the blockchain, so smart contracts do not have access to whispered messages. 32 | * 33 | * [[https://jar-download.com/javaDoc/org.web3j/core/3.0.2/index.html?org/web3j/protocol/core/methods/response/EthBlock.html EthBlock]] 34 | * and its internal types such as 35 | * [[https://jar-download.com/javaDoc/org.web3j/core/3.0.2/index.html?org/web3j/protocol/core/methods/response/EthBlock.Block.html Block]], 36 | * [[https://jar-download.com/javaDoc/org.web3j/core/3.0.2/index.html?org/web3j/protocol/core/methods/response/EthBlock.TransactionObject.html TransactionObject]] and 37 | * [[https://jar-download.com/javaDoc/org.web3j/core/3.0.2/index.html?org/web3j/protocol/core/methods/response/EthBlock.TransactionResult.html TransactionResult]] 38 | * are returned by the following methods of [[com.micronautics.web3j.EthereumSynchronous]] and [[com.micronautics.web3j.EthereumASynchronous]]: 39 | * `blockByHash`, `blockByNumber`, `uncleByBlockHashAndIndex`, `uncleByBlockNumberAndIndex`. 40 | * */ 41 | package object web3j { 42 | /** Enriches `response.EthBlock.Block` with convenience methods */ 43 | implicit class RichBlock(block: response.EthBlock.Block) { 44 | def javaTime = new java.util.Date(block.getTimestamp.longValue * 1000) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/resources/basic_info_getter.sol: -------------------------------------------------------------------------------- 1 | /* From https://raw.githubusercontent.com/fivedogit/solidity-baby-steps/master/contracts/15_basic_info_getter.sol 2 | * This is a demonstration of the various global variables available to contracts. 3 | * This list is probably not exhaustive, especially weeks and months from now. (9/2015) */ 4 | 5 | pragma solidity ^0.4.18; 6 | 7 | contract basicInfoGetter { 8 | address creator; 9 | 10 | constructor() public { 11 | creator = msg.sender; 12 | } 13 | 14 | function getCurrentMinerAddress() public view returns (address) { // get CURRENT block miner's address, 15 | // not necessarily the address of the miner when this block was born 16 | return block.coinbase; 17 | } 18 | 19 | function getCurrentDifficulty() public view returns (uint) { 20 | return block.difficulty; 21 | } 22 | 23 | function getCurrentGaslimit() public view returns (uint) { // the most gas that can be spent on any given transaction right now 24 | return block.gaslimit; 25 | } 26 | 27 | function getCurrentBlockNumber() public view returns (uint) { 28 | return block.number; 29 | } 30 | 31 | function getBlockTimestamp() public view returns (uint) { // returns current block timestamp in SECONDS (not ms) from epoch 32 | return block.timestamp; 33 | // also "now" == "block.timestamp", as in "return now;" 34 | } 35 | 36 | function getMsgData() public pure returns (bytes) { // The data of a call to this function. Always returns "0xc8e7ca2e" for me. 37 | // adding an input parameter would probably change it with each diff call? 38 | return msg.data; 39 | } 40 | 41 | function getMsgSender() public view returns (address) { // Returns the address of whomever made this call 42 | // (i.e. not necessarily the creator of the contract) 43 | return msg.sender; 44 | } 45 | 46 | function getMsgValue() public payable returns (uint) { // returns amt of wei sent with this call 47 | return msg.value; 48 | } 49 | 50 | /*** A note about gas and gasprice: 51 | Every transaction must specify a quantity of "gas" that it is willing to consume (called startgas), 52 | and the fee that it is willing to pay per unit gas (gasprice). At the start of execution, 53 | startgas * gasprice ether are removed from the transaction sender's account. 54 | Whatever is not used is immediately refunded. 55 | */ 56 | 57 | function getMsgGas() public view returns (uint) { 58 | return gasleft(); 59 | } 60 | 61 | function getTxGasprice() public view returns (uint) { 62 | return tx.gasprice; // "gasprice" is the amount of gas the sender was *willing* to pay. 50000000 for me. (geth default) 63 | } 64 | 65 | function getTxOrigin() public view returns (address) { // returns sender of the transaction 66 | // What if there is a chain of calls? I think it returns the first sender, whoever provided the gas. 67 | return msg.sender; 68 | } 69 | 70 | function getContractAddress() public view returns (address) { 71 | return this; 72 | } 73 | 74 | function getContractBalance() public view returns (uint) { 75 | return address(this).balance; 76 | } 77 | 78 | /********** 79 | Standard kill() function to recover funds 80 | **********/ 81 | 82 | function kill() public { 83 | if (msg.sender == creator) 84 | selfdestruct(creator); 85 | // kills this contract and sends remaining funds back to creator 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/test/scala/EtherTest.scala: -------------------------------------------------------------------------------- 1 | import com.micronautics.web3j.Ether 2 | import com.micronautics.web3j.Ether._ 3 | import org.scalatest._ 4 | import org.scalatest.Matchers._ 5 | 6 | class EtherTest extends WordSpec { 7 | val wei: Ether = Ether(e(0)) 8 | val kWei: Ether = Ether(e(3)) 9 | val mWei: Ether = Ether(e(6)) 10 | val gWei: Ether = Ether(e(9)) 11 | val szabo: Ether = Ether(e(12)) 12 | val finney: Ether = Ether(e(15)) 13 | val ether: Ether = Ether(e(18)) 14 | val kEther: Ether = Ether(e(21)) 15 | val mEther: Ether = Ether(e(24)) 16 | val gEther: Ether = Ether(e(27)) 17 | 18 | "Ether" should { 19 | "compare" in { 20 | wei shouldBe wei 21 | kWei should be > wei 22 | kWei should be >= wei 23 | wei should be < kWei 24 | wei should be <= kWei 25 | } 26 | 27 | "support math" in { 28 | wei + wei shouldBe Ether(2) 29 | wei - 1 shouldBe Ether.zero 30 | wei - 2 shouldBe Ether(-1) 31 | wei + 2 shouldBe Ether(3) 32 | wei * 4 shouldBe Ether(4) 33 | 34 | kWei + kWei shouldBe Ether(e(3) * 2) 35 | kWei - 1000 shouldBe Ether.zero 36 | kWei - 2000 shouldBe Ether(e(3) * -1) 37 | kWei + 2000 shouldBe Ether(e(3) * 3) 38 | kWei * 4 shouldBe Ether(e(3) * 4) 39 | } 40 | 41 | "convert properly" in { 42 | Ether.fromWei(BigInt(1)) shouldBe wei 43 | Ether.fromWei(BigDecimal(1)) shouldBe wei 44 | Ether.fromWei(1) shouldBe wei 45 | Ether.fromWei(1.0) shouldBe wei 46 | Ether.fromWei(1.0) shouldBe wei 47 | Ether.fromWei(1) shouldBe wei 48 | 49 | Ether.fromKWei(BigInt(1)) shouldBe kWei 50 | Ether.fromKWei(BigDecimal(1)) shouldBe kWei 51 | Ether.fromKWei(1) shouldBe kWei 52 | Ether.fromKWei(1.0) shouldBe kWei 53 | Ether.fromKWei(1.0) shouldBe kWei 54 | Ether.fromKWei(1) shouldBe kWei 55 | 56 | Ether.fromMWei(BigInt(1)) shouldBe mWei 57 | Ether.fromMWei(BigDecimal(1)) shouldBe mWei 58 | Ether.fromMWei(1) shouldBe mWei 59 | Ether.fromMWei(1.0) shouldBe mWei 60 | Ether.fromMWei(1.0) shouldBe mWei 61 | Ether.fromMWei(1) shouldBe mWei 62 | 63 | Ether.fromGWei(BigInt(1)) shouldBe gWei 64 | Ether.fromGWei(BigDecimal(1)) shouldBe gWei 65 | Ether.fromGWei(1) shouldBe gWei 66 | Ether.fromGWei(1.0) shouldBe gWei 67 | Ether.fromGWei(1.0) shouldBe gWei 68 | Ether.fromGWei(1) shouldBe gWei 69 | 70 | Ether.fromSzabo(BigInt(1)) shouldBe szabo 71 | Ether.fromSzabo(BigDecimal(1)) shouldBe szabo 72 | Ether.fromSzabo(1) shouldBe szabo 73 | Ether.fromSzabo(1.0) shouldBe szabo 74 | Ether.fromSzabo(1.0) shouldBe szabo 75 | Ether.fromSzabo(1) shouldBe szabo 76 | 77 | Ether.fromFinney(BigInt(1)) shouldBe finney 78 | Ether.fromFinney(BigDecimal(1)) shouldBe finney 79 | Ether.fromFinney(1) shouldBe finney 80 | Ether.fromFinney(1.0) shouldBe finney 81 | Ether.fromFinney(1.0) shouldBe finney 82 | Ether.fromFinney(1) shouldBe finney 83 | 84 | Ether.fromEther(BigInt(1)) shouldBe ether 85 | Ether.fromEther(BigDecimal(1)) shouldBe ether 86 | Ether.fromEther(1) shouldBe ether 87 | Ether.fromEther(1.0) shouldBe ether 88 | Ether.fromEther(1.0) shouldBe ether 89 | Ether.fromEther(1) shouldBe ether 90 | 91 | Ether.fromKEther(BigInt(1)) shouldBe kEther 92 | Ether.fromKEther(BigDecimal(1)) shouldBe kEther 93 | Ether.fromKEther(1) shouldBe kEther 94 | Ether.fromKEther(1.0) shouldBe kEther 95 | Ether.fromKEther(1.0) shouldBe kEther 96 | Ether.fromKEther(1) shouldBe kEther 97 | 98 | Ether.fromMEther(BigInt(1)) shouldBe mEther 99 | Ether.fromMEther(BigDecimal(1)) shouldBe mEther 100 | Ether.fromMEther(1) shouldBe mEther 101 | Ether.fromMEther(1.0) shouldBe mEther 102 | Ether.fromMEther(1.0) shouldBe mEther 103 | Ether.fromMEther(1) shouldBe mEther 104 | 105 | Ether.fromGEther(BigInt(1)) shouldBe gEther 106 | Ether.fromGEther(BigDecimal(1)) shouldBe gEther 107 | Ether.fromGEther(1) shouldBe gEther 108 | Ether.fromGEther(1.0) shouldBe gEther 109 | Ether.fromGEther(1.0) shouldBe gEther 110 | Ether.fromGEther(1) shouldBe gEther 111 | } 112 | } 113 | } 114 | --------------------------------------------------------------------------------