diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..31b7a10
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,12 @@
+# https://editorconfig.org/
+
+root = true
+
+[*]
+trim_trailing_whitespace = true
+insert_final_newline = true
+end_of_line = lf
+charset = utf-8
+tab_width = 4
+indent_size = 4
+indent_style = space
diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
new file mode 100644
index 0000000..1f29bc3
--- /dev/null
+++ b/.github/workflows/php.yml
@@ -0,0 +1,24 @@
+name: ci
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Validate composer.json and composer.lock
+ run: composer validate
+
+ - name: Install dependencies
+ run: composer install --prefer-dist --no-progress --no-suggest
+
+ - name: Run test suite
+ run: composer run-script test
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..efd689e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+.DS_Store
+Thumbs.db
+/.idea
+/.vscode
+
+/vendor
+/coverage
+/build
+composer.phar
+composer.lock
+.phpunit.result.cache
+sample.php
+phpDocumentor.phar
diff --git a/README.md b/README.md
index a03af09..ad7c913 100644
--- a/README.md
+++ b/README.md
@@ -4,23 +4,116 @@
## Usage
-*Placeholder; Rather than starting to delve into the API docs, it'd be great to see what the client looks like in action in this lang plus a rough description what it does. The dev should be able to quickly determine whether the example fits the desired style and problem.*
+Send requests to a Nimiq node using a `NimiqCommunity\RpcClient\NimiqClient` object.
+
+```php
+$config = [
+ 'scheme' => 'http',
+ 'host' => '127.0.0.1',
+ 'port' => 8648,
+ 'user' => 'luna',
+ 'password' => 'moon',
+ 'timeout' => false,
+];
+
+$client = new \NimiqCommunity\RpcClient\NimiqClient($config);
+```
+
+Once we have the client, we can start communicating with the Nimiq node.
+If no `$config` object is given in constructor it will use same defaults as the Nimiq node defaults.
+
+```php
+$client = new \NimiqCommunity\RpcClient\NimiqClient();
+
+// make rpc call to get the block number
+$blockNumber = $client->getBlockNumber();
+
+echo $blockNumber; // displays the block number, for example 748883
+```
## API
-*Placeholder; All the implemented methods with parameters, types, default values, return types*
+The complete [API documentation](docs) is available in the `/docs` folder.
+
+Check out the [Nimiq RPC specs](https://github.com/nimiq/core-js/wiki/JSON-RPC-API) for behind the scene RPC calls.
## Installation
-*Placeholder; how to add this client to a project. Each language comes with a package manager. To be useful for developers, add a package description file that works with the most commonly used package manager for this language. For example have a `package.json` file for JavaScript or `pom.xml` for Java.*
+The recommended way to install Nimiq PHP Client is with Composer. Composer is a dependency management tool for PHP that
+allows you to declare the dependencies your project needs and installs them into your project.
+
+```sh
+# Install Composer
+curl -sS https://getcomposer.org/installer | php
+```
+
+You can add Nimiq PHP Client as a dependency using the composer.phar CLI:
+
+```sh
+php composer.phar require nimiq-community/php-client
+```
+
+Alternatively, you can specify it as a dependency in your project's existing composer.json file:
+
+```json
+{
+ "require": {
+ "nimiq-community/php-client": "^1.0"
+ }
+}
+```
+
+After installing, you need to require Composer's autoloader:
+
+```php
+require 'vendor/autoload.php';
+```
+
+You can find out more on how to install Composer, configure autoloading, and other best-practices for defining dependencies at [getcomposer.org](https://getcomposer.org).
## Contributions
-This implementation was originally contributed by [*Placeholder; Your name with link to GitHub*](https://github.com/nimiq/).
+This implementation was originally contributed by [mariofriz](https://github.com/mariofriz/).
Please send your contributions as pull requests.
Refer to the [issue tracker](https://github.com/nimiq-community/php-client/issues) for ideas.
+### Develop
+
+After cloning the repository, install the dependencies:
+
+```sh
+php composer.phar install
+```
+
+All done, happy coding!
+
+### Testing
+
+Tests are stored in the `/tests` folder and can be run using phpunit:
+
+```sh
+php composer.phar run-script test
+```
+
+To run the tests and generate HTML coverage report:
+
+```sh
+php composer.phar run-script coverage
+```
+
+This will generate the report in `/coverage` folder. [Xdebug](https://xdebug.org/docs/install) is required to generate the coverage report.
+
+### Documentation
+
+The documentation in the `/docs` folder can generated from the source code:
+
+```sh
+php composer.phar run-script docs
+```
+
+It will generate a `README.md` in Github Markdown format.
+
## License
[Apache 2.0](LICENSE.md)
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..2241e75
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,34 @@
+{
+ "name": "nimiq-community/php-client",
+ "description": "Nimiq RPC Client for PHP",
+ "homepage": "https://github.com/nimiq-community/php-client",
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Mario",
+ "role": "Developer"
+ }
+ ],
+ "scripts": {
+ "test": "vendor/bin/phpunit",
+ "coverage": "vendor/bin/phpunit --coverage-html coverage",
+ "docs": "vendor/bin/phpdoc"
+ },
+ "require": {
+ "php": ">=7.1",
+ "guzzlehttp/guzzle": "^6.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.0",
+ "cvuorinen/phpdoc-markdown-public": "^0.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "NimiqCommunity\\RpcClient\\": "src"
+ },
+ "files": [
+ "src/functions.php"
+ ]
+ }
+}
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..3b5e4d5
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,1186 @@
+# Nimiq RPC Client for PHP
+
+## Table of Contents
+
+* [NimiqClient](#nimiqclient)
+ * [__construct](#__construct)
+ * [getPeerCount](#getpeercount)
+ * [getSyncingState](#getsyncingstate)
+ * [getConsensusState](#getconsensusstate)
+ * [getPeerList](#getpeerlist)
+ * [getPeer](#getpeer)
+ * [setPeerState](#setpeerstate)
+ * [sendRawTransaction](#sendrawtransaction)
+ * [createRawTransaction](#createrawtransaction)
+ * [sendTransaction](#sendtransaction)
+ * [getRawTransactionInfo](#getrawtransactioninfo)
+ * [getTransactionByBlockHashAndIndex](#gettransactionbyblockhashandindex)
+ * [getTransactionByBlockNumberAndIndex](#gettransactionbyblocknumberandindex)
+ * [getTransactionByHash](#gettransactionbyhash)
+ * [getTransactionReceipt](#gettransactionreceipt)
+ * [getTransactionsByAddress](#gettransactionsbyaddress)
+ * [getMempoolContent](#getmempoolcontent)
+ * [getMempool](#getmempool)
+ * [getMinFeePerByte](#getminfeeperbyte)
+ * [setMinFeePerByte](#setminfeeperbyte)
+ * [getMiningState](#getminingstate)
+ * [setMiningState](#setminingstate)
+ * [getHashrate](#gethashrate)
+ * [getMinerThreads](#getminerthreads)
+ * [setMinerThreads](#setminerthreads)
+ * [getMinerAddress](#getmineraddress)
+ * [getPool](#getpool)
+ * [setPool](#setpool)
+ * [getPoolConnectionState](#getpoolconnectionstate)
+ * [getPoolConfirmedBalance](#getpoolconfirmedbalance)
+ * [getWork](#getwork)
+ * [getBlockTemplate](#getblocktemplate)
+ * [submitBlock](#submitblock)
+ * [getAccounts](#getaccounts)
+ * [createAccount](#createaccount)
+ * [getBalance](#getbalance)
+ * [getAccount](#getaccount)
+ * [getBlockNumber](#getblocknumber)
+ * [getBlockTransactionCountByHash](#getblocktransactioncountbyhash)
+ * [getBlockTransactionCountByNumber](#getblocktransactioncountbynumber)
+ * [getBlockByHash](#getblockbyhash)
+ * [getBlockByNumber](#getblockbynumber)
+ * [getConstant](#getconstant)
+ * [setConstant](#setconstant)
+ * [resetConstant](#resetconstant)
+ * [setLogLevel](#setloglevel)
+
+## NimiqClient
+
+RPC Client to communicate with a Nimiq Node.
+
+
+
+* Full name: \NimiqCommunity\RpcClient\NimiqClient
+* Parent class:
+
+
+### __construct
+
+Creates a new instance of the Nimiq client.
+
+```php
+NimiqClient::__construct( array $config = array() ): \NimiqCommunity\RpcClient\NimiqClient
+```
+
+`$config` array, all fields are optional:
+```
+$config = [
+ 'scheme' => 'http',
+ 'host' => '127.0.0.1',
+ 'port' => 8648,
+ 'user' => 'luna',
+ 'password' => 'moon',
+ 'timeout' => false,
+];
+```
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$config` | **array** | client config array (optional) |
+
+
+**Return Value:**
+
+new client instance
+
+
+
+---
+
+### getPeerCount
+
+Returns number of peers currently connected to the client.
+
+```php
+NimiqClient::getPeerCount( ): integer
+```
+
+
+
+
+
+**Return Value:**
+
+number of connected peers
+
+
+
+---
+
+### getSyncingState
+
+Returns an object with data about the sync status or false.
+
+```php
+NimiqClient::getSyncingState( ): boolean|\NimiqCommunity\RpcClient\Models\SyncingStatus
+```
+
+
+
+
+
+**Return Value:**
+
+object with sync status data or false, when not syncing
+
+
+
+---
+
+### getConsensusState
+
+Returns information on the current consensus state.
+
+```php
+NimiqClient::getConsensusState( ): string
+```
+
+
+
+
+
+**Return Value:**
+
+string describing the consensus state. ConsensusState::Established is the value for a good state, other values indicate bad state.
+
+
+
+---
+
+### getPeerList
+
+Returns list of peers known to the client.
+
+```php
+NimiqClient::getPeerList( ): array<mixed,\NimiqCommunity\RpcClient\Models\Peer>
+```
+
+
+
+
+
+**Return Value:**
+
+list of peers
+
+
+
+---
+
+### getPeer
+
+Returns the state of the peer.
+
+```php
+NimiqClient::getPeer( string $peer ): \NimiqCommunity\RpcClient\Models\Peer
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$peer` | **string** | address of the peer |
+
+
+**Return Value:**
+
+current state of the peer
+
+
+
+---
+
+### setPeerState
+
+Sets the state of the peer.
+
+```php
+NimiqClient::setPeerState( string $peer, string $command ): \NimiqCommunity\RpcClient\Models\Peer
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$peer` | **string** | address of the peer |
+| `$command` | **string** | command to perform (one of PeerStateCommand::Connect, PeerStateCommand::Disconnect, PeerStateCommand::Ban, PeerStateCommand::Unban) |
+
+
+**Return Value:**
+
+new state of the peer
+
+
+
+---
+
+### sendRawTransaction
+
+Sends a signed message call transaction or a contract creation, if the data field contains code.
+
+```php
+NimiqClient::sendRawTransaction( string $txHex ): string
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$txHex` | **string** | hex-encoded signed transaction |
+
+
+**Return Value:**
+
+hex-encoded transaction hash
+
+
+
+---
+
+### createRawTransaction
+
+Creates and signs a transaction without sending it. The transaction can then be send via sendRawTransaction
+without accidentally replaying it.
+
+```php
+NimiqClient::createRawTransaction( \NimiqCommunity\RpcClient\Models\OutgoingTransaction $tx ): string
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$tx` | **\NimiqCommunity\RpcClient\Models\OutgoingTransaction** | transaction object |
+
+
+**Return Value:**
+
+hex-encoded transaction
+
+
+
+---
+
+### sendTransaction
+
+Creates new message call transaction or a contract creation, if the data field contains code.
+
+```php
+NimiqClient::sendTransaction( \NimiqCommunity\RpcClient\Models\OutgoingTransaction $tx ): string
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$tx` | **\NimiqCommunity\RpcClient\Models\OutgoingTransaction** | transaction object |
+
+
+**Return Value:**
+
+hex-encoded transaction hash
+
+
+
+---
+
+### getRawTransactionInfo
+
+Deserializes hex-encoded transaction and returns a transaction object.
+
+```php
+NimiqClient::getRawTransactionInfo( string $txHex ): \NimiqCommunity\RpcClient\Models\Transaction
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$txHex` | **string** | hex-encoded transaction |
+
+
+**Return Value:**
+
+transaction object
+
+
+
+---
+
+### getTransactionByBlockHashAndIndex
+
+Returns information about a transaction by block hash and transaction index position.
+
+```php
+NimiqClient::getTransactionByBlockHashAndIndex( string $blockHash, integer $txIndex ): null|\NimiqCommunity\RpcClient\Models\Transaction
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$blockHash` | **string** | hash of the block containing the transaction |
+| `$txIndex` | **integer** | index of the transaction in the block |
+
+
+**Return Value:**
+
+transaction object, or null when no transaction was found
+
+
+
+---
+
+### getTransactionByBlockNumberAndIndex
+
+Returns information about a transaction by block number and transaction index position.
+
+```php
+NimiqClient::getTransactionByBlockNumberAndIndex( integer $blockNumber, integer $txIndex ): null|\NimiqCommunity\RpcClient\Models\Transaction
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$blockNumber` | **integer** | height of the block containing the transaction |
+| `$txIndex` | **integer** | index of the transaction in the block |
+
+
+**Return Value:**
+
+transaction object, or null when no transaction was found
+
+
+
+---
+
+### getTransactionByHash
+
+Returns the information about a transaction requested by transaction hash.
+
+```php
+NimiqClient::getTransactionByHash( string $hash ): null|\NimiqCommunity\RpcClient\Models\Transaction
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$hash` | **string** | hash of the transaction |
+
+
+**Return Value:**
+
+transaction object, or null when no transaction was found
+
+
+
+---
+
+### getTransactionReceipt
+
+Returns the receipt of a transaction by transaction hash. The receipt is not available for pending transactions.
+
+```php
+NimiqClient::getTransactionReceipt( string $hash ): \NimiqCommunity\RpcClient\Models\TransactionReceipt
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$hash` | **string** | hash of the transaction |
+
+
+**Return Value:**
+
+transaction receipt
+
+
+
+---
+
+### getTransactionsByAddress
+
+Returns the latest transactions successfully performed by or for an address. This information might change
+when blocks are rewinded on the local state due to forks.
+
+```php
+NimiqClient::getTransactionsByAddress( string $address, integer $limit = 1000 ): array<mixed,\NimiqCommunity\RpcClient\Models\Transaction>
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$address` | **string** | account address |
+| `$limit` | **integer** | (optional, default 1000) number of transactions to return |
+
+
+**Return Value:**
+
+array of transactions linked to the requested address
+
+
+
+---
+
+### getMempoolContent
+
+Returns transactions that are currently in the mempool.
+
+```php
+NimiqClient::getMempoolContent( boolean $includeTransactions = false ): array<mixed,string>|array<mixed,\NimiqCommunity\RpcClient\Models\Transaction>
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$includeTransactions` | **boolean** | if true includes full transactions, if false includes only transaction hashes |
+
+
+**Return Value:**
+
+array of transactions (either represented by the transaction hash or a transaction object)
+
+
+
+---
+
+### getMempool
+
+Returns information on the current mempool situation. This will provide an overview of the number of
+transactions sorted into buckets based on their fee per byte (in smallest unit).
+
+```php
+NimiqClient::getMempool( ): \NimiqCommunity\RpcClient\Models\Mempool
+```
+
+
+
+
+
+**Return Value:**
+
+mempool information
+
+
+
+---
+
+### getMinFeePerByte
+
+Returns the current minimum fee per byte.
+
+```php
+NimiqClient::getMinFeePerByte( ): integer
+```
+
+
+
+
+
+**Return Value:**
+
+current minimum fee per byte
+
+
+
+---
+
+### setMinFeePerByte
+
+Sets the minimum fee per byte.
+
+```php
+NimiqClient::setMinFeePerByte( integer $minFee ): integer
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$minFee` | **integer** | minimum fee per byte |
+
+
+**Return Value:**
+
+new minimum fee per byte
+
+
+
+---
+
+### getMiningState
+
+Returns true if client is actively mining new blocks.
+
+```php
+NimiqClient::getMiningState( ): boolean
+```
+
+
+
+
+
+**Return Value:**
+
+true if the client is mining, otherwise false
+
+
+
+---
+
+### setMiningState
+
+Enables or disables the miner.
+
+```php
+NimiqClient::setMiningState( boolean $enabled ): boolean
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$enabled` | **boolean** | true to start the miner, false to stop |
+
+
+**Return Value:**
+
+true if the client is mining, otherwise false
+
+
+
+---
+
+### getHashrate
+
+Returns the number of hashes per second that the node is mining with.
+
+```php
+NimiqClient::getHashrate( ): float
+```
+
+
+
+
+
+**Return Value:**
+
+number of hashes per second
+
+
+
+---
+
+### getMinerThreads
+
+Returns the number of CPU threads the miner is using.
+
+```php
+NimiqClient::getMinerThreads( ): integer
+```
+
+
+
+
+
+**Return Value:**
+
+current number of miner threads
+
+
+
+---
+
+### setMinerThreads
+
+Sets the number of CPU threads the miner can use.
+
+```php
+NimiqClient::setMinerThreads( integer $threads ): integer
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$threads` | **integer** | number of threads to allocate |
+
+
+**Return Value:**
+
+new number of miner threads
+
+
+
+---
+
+### getMinerAddress
+
+Returns the miner address.
+
+```php
+NimiqClient::getMinerAddress( ): string
+```
+
+
+
+
+
+**Return Value:**
+
+miner address
+
+
+
+---
+
+### getPool
+
+Returns the current pool.
+
+```php
+NimiqClient::getPool( ): null|string
+```
+
+
+
+
+
+**Return Value:**
+
+current pool, or null if not set
+
+
+
+---
+
+### setPool
+
+Sets the mining pool.
+
+```php
+NimiqClient::setPool( boolean|string $pool ): null|string
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$pool` | **boolean|string** | mining pool string (url:port) or boolean to enable/disable pool mining |
+
+
+**Return Value:**
+
+new mining pool, or null if not enabled
+
+
+
+---
+
+### getPoolConnectionState
+
+Returns the connection state to mining pool.
+
+```php
+NimiqClient::getPoolConnectionState( ): integer
+```
+
+
+
+
+
+**Return Value:**
+
+mining pool connection state (0: connected, 1: connecting, 2: closed)
+
+
+
+---
+
+### getPoolConfirmedBalance
+
+Returns the confirmed mining pool balance.
+
+```php
+NimiqClient::getPoolConfirmedBalance( ): float
+```
+
+
+
+
+
+**Return Value:**
+
+confirmed mining pool balance (in smallest unit)
+
+
+
+---
+
+### getWork
+
+Returns instructions to mine the next block. This will consider pool instructions when connected to a pool.
+
+```php
+NimiqClient::getWork( string $address = null, string $extraDataHex = null ): array
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$address` | **string** | address to use as a miner for this block. this overrides the address provided during startup or from the pool. |
+| `$extraDataHex` | **string** | hex-encoded value for the extra data field. this overrides the address provided during startup or from the pool. |
+
+
+**Return Value:**
+
+mining work instructions
+
+
+
+---
+
+### getBlockTemplate
+
+Returns a template to build the next block for mining. This will consider pool instructions when connected
+to a pool.
+
+```php
+NimiqClient::getBlockTemplate( string $address = null, string $extraDataHex = null ): array
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$address` | **string** | address to use as a miner for this block. this overrides the address provided during startup or from the pool. |
+| `$extraDataHex` | **string** | hex-encoded value for the extra data field. this overrides the address provided during startup or from the pool. |
+
+
+**Return Value:**
+
+mining block template
+
+
+
+---
+
+### submitBlock
+
+Submits a block to the node. When the block is valid, the node will forward it to other nodes in the network.
+
+```php
+NimiqClient::submitBlock( string $blockHex )
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$blockHex` | **string** | hex-encoded full block (including header, interlink and body). when submitting work from getWork, remember to include the suffix. |
+
+
+
+
+---
+
+### getAccounts
+
+Returns a list of addresses owned by client.
+
+```php
+NimiqClient::getAccounts( ): array<mixed,\NimiqCommunity\RpcClient\Models\Account>|array<mixed,\NimiqCommunity\RpcClient\Models\VestingContract>|array<mixed,\NimiqCommunity\RpcClient\Models\HashedTimeLockedContract>
+```
+
+
+
+
+
+**Return Value:**
+
+array of accounts owned by the client
+
+
+
+---
+
+### createAccount
+
+Creates a new account and stores its private key in the client store.
+
+```php
+NimiqClient::createAccount( ): \NimiqCommunity\RpcClient\Models\Wallet
+```
+
+
+
+
+
+**Return Value:**
+
+information on the wallet that was created using the command
+
+
+
+---
+
+### getBalance
+
+Returns the balance of the account of given address.
+
+```php
+NimiqClient::getBalance( string $address ): float
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$address` | **string** | address to check for balance |
+
+
+**Return Value:**
+
+the current balance at the specified address (in smallest unit)
+
+
+
+---
+
+### getAccount
+
+Returns details for the account of given address.
+
+```php
+NimiqClient::getAccount( string $address ): \NimiqCommunity\RpcClient\Models\Account|\NimiqCommunity\RpcClient\Models\VestingContract|\NimiqCommunity\RpcClient\Models\HashedTimeLockedContract
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$address` | **string** | address for which to get account details |
+
+
+**Return Value:**
+
+details about the account. returns the default empty basic account for non-existing accounts.
+
+
+
+---
+
+### getBlockNumber
+
+Returns the height of most recent block.
+
+```php
+NimiqClient::getBlockNumber( ): integer
+```
+
+
+
+
+
+**Return Value:**
+
+current block height the client is on
+
+
+
+---
+
+### getBlockTransactionCountByHash
+
+Returns the number of transactions in a block from a block matching the given block hash.
+
+```php
+NimiqClient::getBlockTransactionCountByHash( string $blockHash ): null|integer
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$blockHash` | **string** | hash of the block |
+
+
+**Return Value:**
+
+number of transactions in the block found, or null when no block was found
+
+
+
+---
+
+### getBlockTransactionCountByNumber
+
+Returns the number of transactions in a block matching the given block number.
+
+```php
+NimiqClient::getBlockTransactionCountByNumber( integer $blockNumber ): null|integer
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$blockNumber` | **integer** | height of the block |
+
+
+**Return Value:**
+
+number of transactions in the block found, or null when no block was found
+
+
+
+---
+
+### getBlockByHash
+
+Returns information about a block by hash.
+
+```php
+NimiqClient::getBlockByHash( string $blockHash, boolean $includeTransactions = false ): null|\NimiqCommunity\RpcClient\Models\Block
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$blockHash` | **string** | hash of the block to gather information on |
+| `$includeTransactions` | **boolean** | if true includes full transactions, if false (default) includes only transaction hashes |
+
+
+**Return Value:**
+
+block object, or null when no block was found
+
+
+
+---
+
+### getBlockByNumber
+
+Returns information about a block by block number.
+
+```php
+NimiqClient::getBlockByNumber( integer $blockNumber, boolean $includeTransactions = false ): null|\NimiqCommunity\RpcClient\Models\Block
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$blockNumber` | **integer** | height of the block to gather information on |
+| `$includeTransactions` | **boolean** | if true includes full transactions, if false (default) includes only transaction hashes |
+
+
+**Return Value:**
+
+block object, or null when no block was found
+
+
+
+---
+
+### getConstant
+
+Returns the value of a constant.
+
+```php
+NimiqClient::getConstant( string $constant ): integer
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$constant` | **string** | name of the constant |
+
+
+**Return Value:**
+
+current value of the constant
+
+
+
+---
+
+### setConstant
+
+Sets the value of a constants.
+
+```php
+NimiqClient::setConstant( string $constant, integer $value ): integer
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$constant` | **string** | name of the constant |
+| `$value` | **integer** | value to set |
+
+
+**Return Value:**
+
+new value of the constant
+
+
+
+---
+
+### resetConstant
+
+Resets the constant to default value.
+
+```php
+NimiqClient::resetConstant( string $constant ): integer
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$constant` | **string** | name of the constant |
+
+
+**Return Value:**
+
+new value of the constant
+
+
+
+---
+
+### setLogLevel
+
+Sets the log level of the node.
+
+```php
+NimiqClient::setLogLevel( string $tag, string $level ): boolean
+```
+
+
+
+
+**Parameters:**
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `$tag` | **string** | if '*' the log level is set globally, otherwise the log level is applied only on this tag |
+| `$level` | **string** | minimum log level to display (trace, verbose, debug, info, warn, error, assert) |
+
+
+**Return Value:**
+
+true if set successfully, otherwise false
+
+
+
+---
+
+
+
+--------
+> This document was automatically generated from source code comments on 2020-06-17 using [phpDocumentor](http://www.phpdoc.org/) and [cvuorinen/phpdoc-markdown-public](https://github.com/cvuorinen/phpdoc-markdown-public)
diff --git a/phpdoc.xml b/phpdoc.xml
new file mode 100644
index 0000000..ac4fb79
--- /dev/null
+++ b/phpdoc.xml
@@ -0,0 +1,16 @@
+
+
+ Nimiq RPC Client for PHP
+
+ build
+
+
+ docs
+
+
+
+
+
+ src/NimiqClient.php
+
+
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..a65f891
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ tests
+
+
+
+
+ ./src
+
+
+
diff --git a/src/Client.php b/src/Client.php
new file mode 100644
index 0000000..14af0d4
--- /dev/null
+++ b/src/Client.php
@@ -0,0 +1,126 @@
+ 'http',
+ 'host' => '127.0.0.1',
+ 'port' => 8648,
+ 'user' => null,
+ 'password' => null,
+ 'timeout' => false,
+ ];
+
+ /**
+ * URL path.
+ *
+ * @var string
+ */
+ protected $path = '/';
+
+ /**
+ * JSON-RPC Id.
+ *
+ * @var int
+ */
+ protected $rpcId = 0;
+
+ public function __construct($config = [])
+ {
+ $this->config = array_merge($this->config, $config);
+
+ // construct http client
+ $httpClient = new GuzzleHttp([
+ 'base_uri' => $this->getBaseUri(),
+ 'auth' => $this->getAuth(),
+ 'timeout' => (float) $this->config['timeout'],
+ 'connect_timeout' => (float) $this->config['timeout'],
+ ]);
+
+ $this->setClient($httpClient);
+ }
+
+ /**
+ * Makes request to Nimiq Node.
+ *
+ * @param mixed $params
+ */
+ public function request(string $method, ...$params)
+ {
+ $originalResponse = $this->client->post($this->path, $this->makeJson($method, $params));
+
+ $response = new NimiqResponse($originalResponse);
+
+ if ($response->hasError()) {
+ throw new BadMethodCallException($response->getError()['message'], $response->getError()['code']);
+ }
+
+ if ($response->hasResult()) {
+ return $response->getResult();
+ }
+ }
+
+ /**
+ * Gets authentication array.
+ */
+ public function getAuth(): array
+ {
+ return [
+ $this->config['user'],
+ $this->config['password'],
+ ];
+ }
+
+ /**
+ * Gets the base uri.
+ */
+ public function getBaseUri(): string
+ {
+ return $this->config['scheme'] . '://' . $this->config['host'] . ':' . $this->config['port'];
+ }
+
+ /**
+ * Sets the HTTP client.
+ */
+ public function setClient(GuzzleHttp $client)
+ {
+ $this->client = $client;
+ }
+
+ /**
+ * Construct json request.
+ *
+ * @param mixed $params
+ */
+ protected function makeJson(string $method, $params = []): array
+ {
+ return [
+ 'json' => [
+ 'jsonrpc' => '2.0',
+ 'method' => $method,
+ 'params' => (array) $params,
+ 'id' => $this->rpcId++,
+ ],
+ ];
+ }
+}
diff --git a/src/Constants/AccountType.php b/src/Constants/AccountType.php
new file mode 100644
index 0000000..18a6f3e
--- /dev/null
+++ b/src/Constants/AccountType.php
@@ -0,0 +1,21 @@
+ 0
+ && is_array($attributes['transactions'][0]);
+
+ if ($hasFullTransactions) {
+ $normalized['transactions'] = array_map(function ($rawTransaction) {
+ return new Transaction($rawTransaction);
+ }, $normalized['transactions']);
+ }
+
+ parent::__construct($normalized);
+ }
+}
diff --git a/src/Models/HashedTimeLockedContract.php b/src/Models/HashedTimeLockedContract.php
new file mode 100644
index 0000000..f1afbb9
--- /dev/null
+++ b/src/Models/HashedTimeLockedContract.php
@@ -0,0 +1,51 @@
+fill($attributes);
+ }
+
+ /**
+ * Fill the model with an array of attributes.
+ *
+ * @param array $attributes
+ *
+ * @return $this
+ */
+ public function fill($attributes = [])
+ {
+ foreach ($attributes as $key => $value) {
+ if (property_exists(static::class, $key)) {
+ $this->{$key} = $value;
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/src/Models/OutgoingTransaction.php b/src/Models/OutgoingTransaction.php
new file mode 100644
index 0000000..963d692
--- /dev/null
+++ b/src/Models/OutgoingTransaction.php
@@ -0,0 +1,61 @@
+ $this->from,
+ 'fromType' => $this->fromType,
+ 'to' => $this->to,
+ 'toType' => $this->toType,
+ 'value' => $this->value,
+ 'fee' => $this->fee,
+ 'data' => $this->data,
+ ];
+ }
+}
diff --git a/src/Models/Peer.php b/src/Models/Peer.php
new file mode 100644
index 0000000..e479c7e
--- /dev/null
+++ b/src/Models/Peer.php
@@ -0,0 +1,56 @@
+ 'http',
+ * 'host' => '127.0.0.1',
+ * 'port' => 8648,
+ * 'user' => 'luna',
+ * 'password' => 'moon',
+ * 'timeout' => false,
+ * ];
+ * ```
+ *
+ * @param array $config client config array (optional)
+ *
+ * @return NimiqClient new client instance
+ */
+ public function __construct($config = [])
+ {
+ parent::__construct($config);
+ }
+
+ /**
+ * Returns number of peers currently connected to the client.
+ *
+ * @return int number of connected peers
+ */
+ public function getPeerCount()
+ {
+ return $this->request('peerCount');
+ }
+
+ /**
+ * Returns an object with data about the sync status or false.
+ *
+ * @return bool|SyncingStatus object with sync status data or false, when not syncing
+ */
+ public function getSyncingState()
+ {
+ $result = $this->request('syncing');
+
+ if (is_bool($result)) {
+ return $result;
+ }
+
+ return new SyncingStatus($result);
+ }
+
+ /**
+ * Returns information on the current consensus state.
+ *
+ * @return string string describing the consensus state. ConsensusState::Established is the value for a good state, other values indicate bad state.
+ */
+ public function getConsensusState()
+ {
+ return $this->request('consensus');
+ }
+
+ /**
+ * Returns list of peers known to the client.
+ *
+ * @return Peer[] list of peers
+ */
+ public function getPeerList()
+ {
+ $result = $this->request('peerList');
+
+ return array_map(function ($rawPeer) {
+ return new Peer($rawPeer);
+ }, $result);
+ }
+
+ /**
+ * Returns the state of the peer.
+ *
+ * @param string $peer address of the peer
+ *
+ * @return Peer current state of the peer
+ */
+ public function getPeer($peer)
+ {
+ $result = $this->request('peerState', $peer);
+
+ return new Peer($result);
+ }
+
+ /**
+ * Sets the state of the peer.
+ *
+ * @param string $peer address of the peer
+ * @param string $command command to perform (one of PeerStateCommand::Connect, PeerStateCommand::Disconnect, PeerStateCommand::Ban, PeerStateCommand::Unban)
+ *
+ * @return Peer new state of the peer
+ */
+ public function setPeerState(string $peer, string $command)
+ {
+ $result = $this->request('peerState', $peer, $command);
+
+ return new Peer($result);
+ }
+
+ /**
+ * Sends a signed message call transaction or a contract creation, if the data field contains code.
+ *
+ * @param string $txHex hex-encoded signed transaction
+ *
+ * @return string hex-encoded transaction hash
+ */
+ public function sendRawTransaction($txHex)
+ {
+ return $this->request('sendRawTransaction', $txHex);
+ }
+
+ /**
+ * Creates and signs a transaction without sending it. The transaction can then be send via sendRawTransaction
+ * without accidentally replaying it.
+ *
+ * @param OutgoingTransaction $tx transaction object
+ *
+ * @return string hex-encoded transaction
+ */
+ public function createRawTransaction(OutgoingTransaction $tx)
+ {
+ return $this->request('createRawTransaction', $tx->toArray());
+ }
+
+ /**
+ * Creates new message call transaction or a contract creation, if the data field contains code.
+ *
+ * @param OutgoingTransaction $tx transaction object
+ *
+ * @return string hex-encoded transaction hash
+ */
+ public function sendTransaction(OutgoingTransaction $tx)
+ {
+ return $this->request('sendTransaction', $tx->toArray());
+ }
+
+ /**
+ * Deserializes hex-encoded transaction and returns a transaction object.
+ *
+ * @param string $txHex hex-encoded transaction
+ *
+ * @return Transaction transaction object
+ */
+ public function getRawTransactionInfo($txHex)
+ {
+ $result = $this->request('getRawTransactionInfo', $txHex);
+
+ return new Transaction($result);
+ }
+
+ /**
+ * Returns information about a transaction by block hash and transaction index position.
+ *
+ * @param string $blockHash hash of the block containing the transaction
+ * @param int $txIndex index of the transaction in the block
+ *
+ * @return null|Transaction transaction object, or null when no transaction was found
+ */
+ public function getTransactionByBlockHashAndIndex($blockHash, $txIndex)
+ {
+ $result = $this->request('getTransactionByBlockHashAndIndex', $blockHash, $txIndex);
+
+ if (is_null($result)) {
+ return null;
+ }
+
+ return new Transaction($result);
+ }
+
+ /**
+ * Returns information about a transaction by block number and transaction index position.
+ *
+ * @param int $blockNumber height of the block containing the transaction
+ * @param int $txIndex index of the transaction in the block
+ *
+ * @return null|Transaction transaction object, or null when no transaction was found
+ */
+ public function getTransactionByBlockNumberAndIndex($blockNumber, $txIndex)
+ {
+ $result = $this->request('getTransactionByBlockNumberAndIndex', $blockNumber, $txIndex);
+
+ if (is_null($result)) {
+ return null;
+ }
+
+ return new Transaction($result);
+ }
+
+ /**
+ * Returns the information about a transaction requested by transaction hash.
+ *
+ * @param string $hash hash of the transaction
+ *
+ * @return null|Transaction transaction object, or null when no transaction was found
+ */
+ public function getTransactionByHash($hash)
+ {
+ $result = $this->request('getTransactionByHash', $hash);
+
+ if (is_null($result)) {
+ return null;
+ }
+
+ return new Transaction($result);
+ }
+
+ /**
+ * Returns the receipt of a transaction by transaction hash. The receipt is not available for pending transactions.
+ *
+ * @param string $hash hash of the transaction
+ *
+ * @return TransactionReceipt transaction receipt
+ */
+ public function getTransactionReceipt($hash)
+ {
+ $result = $this->request('getTransactionReceipt', $hash);
+
+ if (is_null($result)) {
+ return null;
+ }
+
+ return new TransactionReceipt($result);
+ }
+
+ /**
+ * Returns the latest transactions successfully performed by or for an address. This information might change
+ * when blocks are rewinded on the local state due to forks.
+ *
+ * @param string $address account address
+ * @param int $limit (optional, default 1000) number of transactions to return
+ *
+ * @return Transaction[] array of transactions linked to the requested address
+ */
+ public function getTransactionsByAddress($address, $limit = 1000)
+ {
+ $result = $this->request('getTransactionsByAddress', $address, $limit);
+
+ return array_map(function ($rawTransaction) {
+ return new Transaction($rawTransaction);
+ }, $result);
+ }
+
+ /**
+ * Returns transactions that are currently in the mempool.
+ *
+ * @param bool $includeTransactions if true includes full transactions, if false includes only transaction hashes
+ *
+ * @return string[]|Transaction[] array of transactions (either represented by the transaction hash or a transaction object)
+ */
+ public function getMempoolContent($includeTransactions = false)
+ {
+ $result = $this->request('mempoolContent', $includeTransactions);
+
+ if ($includeTransactions) {
+ return array_map(function ($rawTransaction) {
+ return new Transaction($rawTransaction);
+ }, $result);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns information on the current mempool situation. This will provide an overview of the number of
+ * transactions sorted into buckets based on their fee per byte (in smallest unit).
+ *
+ * @return Mempool mempool information
+ */
+ public function getMempool()
+ {
+ $result = $this->request('mempool');
+
+ return new Mempool($result);
+ }
+
+ /**
+ * Returns the current minimum fee per byte.
+ *
+ * @return int current minimum fee per byte
+ */
+ public function getMinFeePerByte()
+ {
+ return $this->request('minFeePerByte');
+ }
+
+ /**
+ * Sets the minimum fee per byte.
+ *
+ * @param int $minFee minimum fee per byte
+ *
+ * @return int new minimum fee per byte
+ */
+ public function setMinFeePerByte($minFee)
+ {
+ return $this->request('minFeePerByte', $minFee);
+ }
+
+ /**
+ * Returns true if client is actively mining new blocks.
+ *
+ * @return bool true if the client is mining, otherwise false
+ */
+ public function getMiningState()
+ {
+ return $this->request('mining');
+ }
+
+ /**
+ * Enables or disables the miner.
+ *
+ * @param bool $enabled true to start the miner, false to stop
+ *
+ * @return bool true if the client is mining, otherwise false
+ */
+ public function setMiningState($enabled)
+ {
+ return $this->request('mining', $enabled);
+ }
+
+ /**
+ * Returns the number of hashes per second that the node is mining with.
+ *
+ * @return float number of hashes per second
+ */
+ public function getHashrate()
+ {
+ return $this->request('hashrate');
+ }
+
+ /**
+ * Returns the number of CPU threads the miner is using.
+ *
+ * @return int current number of miner threads
+ */
+ public function getMinerThreads()
+ {
+ return $this->request('minerThreads');
+ }
+
+ /**
+ * Sets the number of CPU threads the miner can use.
+ *
+ * @param int $threads number of threads to allocate
+ *
+ * @return int new number of miner threads
+ */
+ public function setMinerThreads($threads)
+ {
+ return $this->request('minerThreads', $threads);
+ }
+
+ /**
+ * Returns the miner address.
+ *
+ * @return string miner address
+ */
+ public function getMinerAddress()
+ {
+ return $this->request('minerAddress');
+ }
+
+ /**
+ * Returns the current pool.
+ *
+ * @return null|string current pool, or null if not set
+ */
+ public function getPool()
+ {
+ return $this->request('pool');
+ }
+
+ /**
+ * Sets the mining pool.
+ *
+ * @param bool|string $pool mining pool string (url:port) or boolean to enable/disable pool mining
+ *
+ * @return null|string new mining pool, or null if not enabled
+ */
+ public function setPool($pool)
+ {
+ return $this->request('pool', $pool);
+ }
+
+ /**
+ * Returns the connection state to mining pool.
+ *
+ * @return int mining pool connection state (0: connected, 1: connecting, 2: closed)
+ */
+ public function getPoolConnectionState()
+ {
+ return $this->request('poolConnectionState');
+ }
+
+ /**
+ * Returns the confirmed mining pool balance.
+ *
+ * @return float confirmed mining pool balance (in smallest unit)
+ */
+ public function getPoolConfirmedBalance()
+ {
+ return $this->request('poolConfirmedBalance');
+ }
+
+ /**
+ * Returns instructions to mine the next block. This will consider pool instructions when connected to a pool.
+ *
+ * @param string $address address to use as a miner for this block. this overrides the address provided during startup or from the pool.
+ * @param string $extraDataHex hex-encoded value for the extra data field. this overrides the address provided during startup or from the pool.
+ *
+ * @return array mining work instructions
+ */
+ public function getWork($address = null, $extraDataHex = null)
+ {
+ return $this->request('getWork', $address, $extraDataHex);
+ }
+
+ /**
+ * Returns a template to build the next block for mining. This will consider pool instructions when connected
+ * to a pool.
+ *
+ * @param string $address address to use as a miner for this block. this overrides the address provided during startup or from the pool.
+ * @param string $extraDataHex hex-encoded value for the extra data field. this overrides the address provided during startup or from the pool.
+ *
+ * @return array mining block template
+ */
+ public function getBlockTemplate($address = null, $extraDataHex = null)
+ {
+ return $this->request('getBlockTemplate', $address, $extraDataHex);
+ }
+
+ /**
+ * Submits a block to the node. When the block is valid, the node will forward it to other nodes in the network.
+ *
+ * @param string $blockHex hex-encoded full block (including header, interlink and body). when submitting work from getWork, remember to include the suffix.
+ */
+ public function submitBlock($blockHex)
+ {
+ $this->request('submitBlock', $blockHex);
+ }
+
+ /**
+ * Returns a list of addresses owned by client.
+ *
+ * @return Account[]|VestingContract[]|HashedTimeLockedContract[] array of accounts owned by the client
+ */
+ public function getAccounts()
+ {
+ $result = $this->request('accounts');
+
+ return array_map(function ($rawAccount) {
+ return $this->convertAccountInfoToModel($rawAccount);
+ }, $result);
+ }
+
+ /**
+ * Creates a new account and stores its private key in the client store.
+ *
+ * @return Wallet information on the wallet that was created using the command
+ */
+ public function createAccount()
+ {
+ $result = $this->request('createAccount');
+
+ return new Wallet($result);
+ }
+
+ /**
+ * Returns the balance of the account of given address.
+ *
+ * @param string $address address to check for balance
+ *
+ * @return float the current balance at the specified address (in smallest unit)
+ */
+ public function getBalance($address)
+ {
+ return $this->request('getBalance', $address);
+ }
+
+ /**
+ * Returns details for the account of given address.
+ *
+ * @param string $address address for which to get account details
+ *
+ * @return Account|VestingContract|HashedTimeLockedContract details about the account. returns the default empty basic account for non-existing accounts.
+ */
+ public function getAccount($address)
+ {
+ $result = $this->request('getAccount', $address);
+
+ return $this->convertAccountInfoToModel($result);
+ }
+
+ /**
+ * Returns the height of most recent block.
+ *
+ * @return int current block height the client is on
+ */
+ public function getBlockNumber()
+ {
+ return $this->request('blockNumber');
+ }
+
+ /**
+ * Returns the number of transactions in a block from a block matching the given block hash.
+ *
+ * @param string $blockHash hash of the block
+ *
+ * @return null|int number of transactions in the block found, or null when no block was found
+ */
+ public function getBlockTransactionCountByHash($blockHash)
+ {
+ return $this->request('getBlockTransactionCountByHash', $blockHash);
+ }
+
+ /**
+ * Returns the number of transactions in a block matching the given block number.
+ *
+ * @param int $blockNumber height of the block
+ *
+ * @return null|int number of transactions in the block found, or null when no block was found
+ */
+ public function getBlockTransactionCountByNumber($blockNumber)
+ {
+ return $this->request('getBlockTransactionCountByNumber', $blockNumber);
+ }
+
+ /**
+ * Returns information about a block by hash.
+ *
+ * @param string $blockHash hash of the block to gather information on
+ * @param bool $includeTransactions if true includes full transactions, if false (default) includes only transaction hashes
+ *
+ * @return null|Block block object, or null when no block was found
+ */
+ public function getBlockByHash($blockHash, $includeTransactions = false)
+ {
+ $result = $this->request('getBlockByHash', $blockHash, $includeTransactions);
+
+ if (is_null($result)) {
+ return null;
+ }
+
+ return new Block($result);
+ }
+
+ /**
+ * Returns information about a block by block number.
+ *
+ * @param int $blockNumber height of the block to gather information on
+ * @param bool $includeTransactions if true includes full transactions, if false (default) includes only transaction hashes
+ *
+ * @return null|Block block object, or null when no block was found
+ */
+ public function getBlockByNumber($blockNumber, $includeTransactions = false)
+ {
+ $result = $this->request('getBlockByNumber', $blockNumber, $includeTransactions);
+
+ if (is_null($result)) {
+ return null;
+ }
+
+ return new Block($result);
+ }
+
+ /**
+ * Returns the value of a constant.
+ *
+ * @param string $constant name of the constant
+ *
+ * @return int current value of the constant
+ */
+ public function getConstant($constant)
+ {
+ return $this->request('constant', $constant);
+ }
+
+ /**
+ * Sets the value of a constants.
+ *
+ * @param string $constant name of the constant
+ * @param int $value value to set
+ *
+ * @return int new value of the constant
+ */
+ public function setConstant($constant, $value)
+ {
+ return $this->request('constant', $constant, $value);
+ }
+
+ /**
+ * Resets the constant to default value.
+ *
+ * @param string $constant name of the constant
+ *
+ * @return int new value of the constant
+ */
+ public function resetConstant($constant)
+ {
+ return $this->request('constant', $constant, 'reset');
+ }
+
+ /**
+ * Sets the log level of the node.
+ *
+ * @param string $tag if '*' the log level is set globally, otherwise the log level is applied only on this tag
+ * @param string $level minimum log level to display (trace, verbose, debug, info, warn, error, assert)
+ *
+ * @return bool true if set successfully, otherwise false
+ */
+ public function setLogLevel($tag, $level)
+ {
+ return $this->request('log', $tag, $level);
+ }
+
+ /**
+ * Create an Account, HTLC or Vesting contract based on the type.
+ *
+ * @param array $rawAccount raw account information from RPC response
+ *
+ * @return Account|HashedTimeLockedContract|VestingContract account model depending on type
+ */
+ private function convertAccountInfoToModel($rawAccount)
+ {
+ switch ($rawAccount['type']) {
+ case AccountType::Vesting:
+ return new VestingContract($rawAccount);
+
+ case AccountType::Htlc:
+ return new HashedTimeLockedContract($rawAccount);
+
+ default:
+ return new Account($rawAccount);
+ }
+ }
+}
diff --git a/src/NimiqResponse.php b/src/NimiqResponse.php
new file mode 100644
index 0000000..51f116d
--- /dev/null
+++ b/src/NimiqResponse.php
@@ -0,0 +1,84 @@
+response = $response;
+ $this->data = json_decode((string) $response->getBody(), true);
+ }
+
+ /**
+ * Gets the RPC id.
+ */
+ public function getId(): int
+ {
+ return $this->data['id'];
+ }
+
+ /**
+ * Checks if response has error.
+ */
+ public function hasError(): bool
+ {
+ return isset($this->data['error']);
+ }
+
+ /**
+ * Gets error array.
+ */
+ public function getError(): array
+ {
+ return $this->data['error'];
+ }
+
+ /**
+ * Checks if response has result.
+ */
+ public function hasResult(): bool
+ {
+ return isset($this->data['result']);
+ }
+
+ /**
+ * Gets result array.
+ */
+ public function getResult()
+ {
+ return $this->data['result'];
+ }
+
+ /**
+ * Gets the original response.
+ */
+ public function getResponse(): ResponseInterface
+ {
+ return $this->response;
+ }
+}
diff --git a/src/functions.php b/src/functions.php
new file mode 100644
index 0000000..062ef5a
--- /dev/null
+++ b/src/functions.php
@@ -0,0 +1,31 @@
+client = new Client();
+ $this->mock = new \GuzzleHttp\Handler\MockHandler();
+
+ $httpClient = new \GuzzleHttp\Client([
+ 'handler' => $this->mock,
+ ]);
+
+ $this->client->setClient($httpClient);
+ }
+
+ public function testClientCanBeInstanciated()
+ {
+ $client = new Client();
+
+ $this->assertInstanceOf(Client::class, $client);
+ }
+
+ public function testClientCalculatesBaseUri()
+ {
+ $client = new Client([
+ 'scheme' => 'https',
+ 'host' => 'localhost',
+ 'port' => '8181',
+ ]);
+
+ $baseUri = $client->getBaseUri();
+
+ $this->assertEquals('https://localhost:8181', $baseUri);
+ }
+
+ public function testClientCalculatesAuthInfo()
+ {
+ $client = new Client([
+ 'user' => 'admin',
+ 'password' => 'root',
+ ]);
+
+ $auth = $client->getAuth();
+
+ $this->assertEquals([
+ 'admin', 'root',
+ ], $auth);
+ }
+
+ public function testClientSendsProperFormattedRequest()
+ {
+ $this->mock->append(new \GuzzleHttp\Psr7\Response(200, [], json_encode([
+ 'jsonrpc' => '2.0',
+ 'id' => 0,
+ 'result' => 1000,
+ ])));
+
+ $this->client->request('test', 'test-string', true, 15, [0, 2, 4], ['key' => 'value']);
+ $request = $this->mock->getLastRequest();
+
+ $this->assertEquals('POST', $request->getMethod());
+
+ $body = json_decode($request->getBody()->getContents(), true);
+
+ $this->assertEquals(0, $body['id']);
+ $this->assertEquals('test', $body['method']);
+ $this->assertEquals('test-string', $body['params'][0]);
+ $this->assertEquals(true, $body['params'][1]);
+ $this->assertEquals(15, $body['params'][2]);
+ $this->assertEquals([0, 2, 4], $body['params'][3]);
+ $this->assertEquals(['key' => 'value'], $body['params'][4]);
+ }
+
+ public function testClientReturnsResponseResult()
+ {
+ $this->mock->append(new \GuzzleHttp\Psr7\Response(200, [], json_encode([
+ 'jsonrpc' => '2.0',
+ 'id' => 0,
+ 'result' => 1000,
+ ])));
+
+ $response = $this->client->request('test', 1000);
+
+ $this->assertEquals(1000, $response);
+ }
+
+ public function testClientHandlesErrorProperly()
+ {
+ $this->mock->append(new \GuzzleHttp\Psr7\Response(200, [], json_encode([
+ 'jsonrpc' => '2.0',
+ 'id' => 0,
+ 'error' => [
+ 'code' => -32601,
+ 'message' => 'Method not found',
+ ],
+ ])));
+
+ $this->expectException(BadMethodCallException::class);
+ $this->expectExceptionCode(-32601);
+ $this->expectExceptionMessage('Method not found');
+
+ $this->client->request('test', 1000);
+ }
+}
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
new file mode 100644
index 0000000..f13d45c
--- /dev/null
+++ b/tests/FunctionsTest.php
@@ -0,0 +1,69 @@
+assertEquals(12, $nim);
+ }
+
+ public function testToNimWithSmallAmount()
+ {
+ $nim = toNim(12000);
+
+ $this->assertEquals(0.12, $nim);
+ }
+
+ public function testToNimWithZero()
+ {
+ $nim = toNim(0);
+
+ $this->assertEquals(0, $nim);
+ }
+
+ public function testToNimWithMoreThan5Decimals()
+ {
+ $nim = toNim(1.01);
+
+ $this->assertEquals(0.00001, $nim);
+ }
+
+ public function testToLuna()
+ {
+ $luna = toLuna(12);
+
+ $this->assertEquals(1200000, $luna);
+ }
+
+ public function testToLunaWithSmallAmount()
+ {
+ $luna = toLuna(0.12);
+
+ $this->assertEquals(12000, $luna);
+ }
+
+ public function testToLunaWithZero()
+ {
+ $luna = toLuna(0);
+
+ $this->assertEquals(0, $luna);
+ }
+
+ public function testToLunaWithMoreThan5Decimals()
+ {
+ $luna = toLuna(1.0000001);
+
+ $this->assertEquals(100000, $luna);
+ }
+}
diff --git a/tests/NimiqClientTest.php b/tests/NimiqClientTest.php
new file mode 100644
index 0000000..3416d5b
--- /dev/null
+++ b/tests/NimiqClientTest.php
@@ -0,0 +1,1181 @@
+client = new NimiqClient();
+ $this->mock = new \GuzzleHttp\Handler\MockHandler();
+
+ $httpClient = new \GuzzleHttp\Client([
+ 'handler' => $this->mock,
+ ]);
+
+ $this->client->setClient($httpClient);
+ }
+
+ public function testNimiqClientCanBeInstanciated()
+ {
+ $client = new NimiqClient();
+
+ $this->assertInstanceOf(NimiqClient::class, $client);
+ }
+
+ public function testGetPeerCount()
+ {
+ $this->appendNextResponse('peerCount/count.json');
+
+ $result = $this->client->getPeerCount();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('peerCount', $body['method']);
+
+ $this->assertEquals(6, $result);
+ }
+
+ public function testGetSyncingStateWhenSyncing()
+ {
+ $this->appendNextResponse('syncing/syncing.json');
+
+ $result = $this->client->getSyncingState();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('syncing', $body['method']);
+
+ $this->assertEquals(578430, $result->startingBlock);
+ $this->assertEquals(586493, $result->currentBlock);
+ $this->assertEquals(586493, $result->highestBlock);
+ }
+
+ public function testGetSyncingStateWhenNotSyncing()
+ {
+ $this->appendNextResponse('syncing/not-syncing.json');
+
+ $result = $this->client->getSyncingState();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('syncing', $body['method']);
+
+ $this->assertEquals(false, $result);
+ }
+
+ public function testGetConsensusState()
+ {
+ $this->appendNextResponse('consensus/syncing.json');
+
+ $result = $this->client->getConsensusState();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('consensus', $body['method']);
+
+ $this->assertEquals(ConsensusState::Syncing, $result);
+ }
+
+ public function testGetPeerListWithPeers()
+ {
+ $this->appendNextResponse('peerList/list.json');
+
+ $result = $this->client->getPeerList();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('peerList', $body['method']);
+
+ $this->assertEquals(count($result), 2);
+ $this->assertInstanceOf(Peer::class, $result[0]);
+ $this->assertEquals('b99034c552e9c0fd34eb95c1cdf17f5e', $result[0]->id);
+ $this->assertEquals('wss://seed1.nimiq-testnet.com:8080/b99034c552e9c0fd34eb95c1cdf17f5e', $result[0]->address);
+ $this->assertEquals(AddressState::Established, $result[0]->addressState);
+ $this->assertEquals(ConnectionState::Established, $result[0]->connectionState);
+
+ $this->assertInstanceOf(Peer::class, $result[1]);
+ $this->assertEquals('e37dca72802c972d45b37735e9595cf0', $result[1]->id);
+ $this->assertEquals('wss://seed4.nimiq-testnet.com:8080/e37dca72802c972d45b37735e9595cf0', $result[1]->address);
+ $this->assertEquals(AddressState::Failed, $result[1]->addressState);
+ $this->assertEquals(null, $result[1]->connectionState);
+ }
+
+ public function testGetPeerListWhenEmpty()
+ {
+ $this->appendNextResponse('peerList/empty-list.json');
+
+ $result = $this->client->getPeerList();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('peerList', $body['method']);
+
+ $this->assertEquals(count($result), 0);
+ }
+
+ public function testGetPeerNormal()
+ {
+ $this->appendNextResponse('peerState/normal.json');
+
+ $result = $this->client->getPeer('wss://seed1.nimiq-testnet.com:8080/b99034c552e9c0fd34eb95c1cdf17f5e');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('peerState', $body['method']);
+ $this->assertEquals('wss://seed1.nimiq-testnet.com:8080/b99034c552e9c0fd34eb95c1cdf17f5e', $body['params'][0]);
+
+ $this->assertInstanceOf(Peer::class, $result);
+ $this->assertEquals('b99034c552e9c0fd34eb95c1cdf17f5e', $result->id);
+ $this->assertEquals('wss://seed1.nimiq-testnet.com:8080/b99034c552e9c0fd34eb95c1cdf17f5e', $result->address);
+ $this->assertEquals(AddressState::Established, $result->addressState);
+ $this->assertEquals(ConnectionState::Established, $result->connectionState);
+ }
+
+ public function testGetPeerFailed()
+ {
+ $this->appendNextResponse('peerState/failed.json');
+
+ $result = $this->client->getPeer('wss://seed4.nimiq-testnet.com:8080/e37dca72802c972d45b37735e9595cf0');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('peerState', $body['method']);
+ $this->assertEquals('wss://seed4.nimiq-testnet.com:8080/e37dca72802c972d45b37735e9595cf0', $body['params'][0]);
+
+ $this->assertInstanceOf(Peer::class, $result);
+ $this->assertEquals('e37dca72802c972d45b37735e9595cf0', $result->id);
+ $this->assertEquals('wss://seed4.nimiq-testnet.com:8080/e37dca72802c972d45b37735e9595cf0', $result->address);
+ $this->assertEquals(AddressState::Failed, $result->addressState);
+ $this->assertEquals(null, $result->connectionState);
+ }
+
+ public function testGetPeerError()
+ {
+ $this->expectException(BadMethodCallException::class);
+
+ $this->appendNextResponse('peerState/error.json');
+
+ $result = $this->client->getPeer('unknown');
+ }
+
+ public function testSetPeerState()
+ {
+ $this->appendNextResponse('peerState/normal.json');
+
+ $result = $this->client->setPeerState('wss://seed1.nimiq-testnet.com:8080/b99034c552e9c0fd34eb95c1cdf17f5e', PeerStateCommand::Connect);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('peerState', $body['method']);
+ $this->assertEquals('wss://seed1.nimiq-testnet.com:8080/b99034c552e9c0fd34eb95c1cdf17f5e', $body['params'][0]);
+ $this->assertEquals('connect', $body['params'][1]);
+
+ $this->assertInstanceOf(Peer::class, $result);
+ $this->assertEquals('b99034c552e9c0fd34eb95c1cdf17f5e', $result->id);
+ $this->assertEquals('wss://seed1.nimiq-testnet.com:8080/b99034c552e9c0fd34eb95c1cdf17f5e', $result->address);
+ $this->assertEquals(AddressState::Established, $result->addressState);
+ $this->assertEquals(ConnectionState::Established, $result->connectionState);
+ }
+
+ public function testSendRawTransaction()
+ {
+ $this->appendNextResponse('sendTransaction/transaction.json');
+
+ $result = $this->client->sendRawTransaction('00c3c0d1af80b84c3b3de4e3d79d5c8cc950e044098c969953d68bf9cee68d7b53305dbaac7514a06dae935e40d599caf1bd8a243c00000000000000010000000000000001000dc2e201b5a1755aec80aa4227d5afc6b0de0fcfede8541f31b3c07b9a85449ea9926c1c958628d85a2b481556034ab3d67ff7de28772520813c84aaaf8108f6297c580c');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('sendRawTransaction', $body['method']);
+ $this->assertEquals('00c3c0d1af80b84c3b3de4e3d79d5c8cc950e044098c969953d68bf9cee68d7b53305dbaac7514a06dae935e40d599caf1bd8a243c00000000000000010000000000000001000dc2e201b5a1755aec80aa4227d5afc6b0de0fcfede8541f31b3c07b9a85449ea9926c1c958628d85a2b481556034ab3d67ff7de28772520813c84aaaf8108f6297c580c', $body['params'][0]);
+
+ $this->assertIsString($result);
+ $this->assertEquals('81cf3f07b6b0646bb16833d57cda801ad5957e264b64705edeef6191fea0ad63', $result);
+ }
+
+ public function testCreateRawTransaction()
+ {
+ $this->appendNextResponse('createRawTransaction/basic.json');
+
+ $transaction = new OutgoingTransaction();
+ $transaction->from = 'NQ39 NY67 X0F0 UTQE 0YER 4JEU B67L UPP8 G0FM';
+ $transaction->fromType = AccountType::Basic;
+ $transaction->to = 'NQ16 61ET MB3M 2JG6 TBLK BR0D B6EA X6XQ L91U';
+ $transaction->toType = AccountType::Basic;
+ $transaction->value = 100000;
+ $transaction->fee = 1;
+
+ $result = $this->client->createRawTransaction($transaction);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('createRawTransaction', $body['method']);
+
+ $param = $body['params'][0];
+ $this->assertEquals($param, [
+ 'from' => 'NQ39 NY67 X0F0 UTQE 0YER 4JEU B67L UPP8 G0FM',
+ 'fromType' => 0,
+ 'to' => 'NQ16 61ET MB3M 2JG6 TBLK BR0D B6EA X6XQ L91U',
+ 'toType' => 0,
+ 'value' => 100000,
+ 'fee' => 1,
+ 'data' => null,
+ ]);
+
+ $this->assertEquals('00c3c0d1af80b84c3b3de4e3d79d5c8cc950e044098c969953d68bf9cee68d7b53305dbaac7514a06dae935e40d599caf1bd8a243c00000000000186a00000000000000001000af84c01239b16cee089836c2af5c7b1dbb22cdc0b4864349f7f3805909aa8cf24e4c1ff0461832e86f3624778a867d5f2ba318f92918ada7ae28d70d40c4ef1d6413802', $result);
+ }
+
+ public function testSendTransaction()
+ {
+ $this->appendNextResponse('sendTransaction/transaction.json');
+
+ $transaction = new OutgoingTransaction();
+ $transaction->from = 'NQ39 NY67 X0F0 UTQE 0YER 4JEU B67L UPP8 G0FM';
+ $transaction->fromType = AccountType::Basic;
+ $transaction->to = 'NQ16 61ET MB3M 2JG6 TBLK BR0D B6EA X6XQ L91U';
+ $transaction->toType = AccountType::Basic;
+ $transaction->value = 1;
+ $transaction->fee = 1;
+
+ $result = $this->client->sendTransaction($transaction);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('sendTransaction', $body['method']);
+
+ $payload = $body['params'][0];
+ $this->assertEquals([
+ 'from' => 'NQ39 NY67 X0F0 UTQE 0YER 4JEU B67L UPP8 G0FM',
+ 'fromType' => 0,
+ 'to' => 'NQ16 61ET MB3M 2JG6 TBLK BR0D B6EA X6XQ L91U',
+ 'toType' => 0,
+ 'value' => 1,
+ 'fee' => 1,
+ 'data' => null,
+ ], $payload);
+
+ $this->assertIsString($result);
+ $this->assertEquals('81cf3f07b6b0646bb16833d57cda801ad5957e264b64705edeef6191fea0ad63', $result);
+ }
+
+ public function testGetRawTransactionInfo()
+ {
+ $this->appendNextResponse('getRawTransactionInfo/basic-transaction.json');
+
+ $result = $this->client->getRawTransactionInfo('00c3c0d1af80b84c3b3de4e3d79d5c8cc950e044098c969953d68bf9cee68d7b53305dbaac7514a06dae935e40d599caf1bd8a243c00000000000186a00000000000000001000af84c01239b16cee089836c2af5c7b1dbb22cdc0b4864349f7f3805909aa8cf24e4c1ff0461832e86f3624778a867d5f2ba318f92918ada7ae28d70d40c4ef1d6413802');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getRawTransactionInfo', $body['method']);
+ $this->assertEquals('00c3c0d1af80b84c3b3de4e3d79d5c8cc950e044098c969953d68bf9cee68d7b53305dbaac7514a06dae935e40d599caf1bd8a243c00000000000186a00000000000000001000af84c01239b16cee089836c2af5c7b1dbb22cdc0b4864349f7f3805909aa8cf24e4c1ff0461832e86f3624778a867d5f2ba318f92918ada7ae28d70d40c4ef1d6413802', $body['params'][0]);
+
+ $this->assertInstanceOf(Transaction::class, $result);
+ $this->assertEquals('7784f2f6eaa076fa5cf0e4d06311ad204b2f485de622231785451181e8129091', $result->hash);
+ $this->assertEquals('b7cc7f01e0e6f0e07dd9249dc598f4e5ee8801f5', $result->from);
+ $this->assertEquals('NQ39 NY67 X0F0 UTQE 0YER 4JEU B67L UPP8 G0FM', $result->fromAddress);
+ $this->assertEquals('305dbaac7514a06dae935e40d599caf1bd8a243c', $result->to);
+ $this->assertEquals('NQ16 61ET MB3M 2JG6 TBLK BR0D B6EA X6XQ L91U', $result->toAddress);
+ $this->assertEquals(100000, $result->value);
+ $this->assertEquals(1, $result->fee);
+ }
+
+ public function testGetTransactionByBlockHashAndIndex()
+ {
+ $this->appendNextResponse('getTransaction/full-transaction.json');
+
+ $result = $this->client->getTransactionByBlockHashAndIndex('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', 0);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionByBlockHashAndIndex', $body['method']);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $body['params'][0]);
+ $this->assertEquals(0, $body['params'][1]);
+
+ $this->assertInstanceOf(Transaction::class, $result);
+ $this->assertEquals('78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430', $result->hash);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $result->blockHash);
+ $this->assertEquals(0, $result->transactionIndex);
+ $this->assertEquals('355b4fe2304a9c818b9f0c3c1aaaf4ad4f6a0279', $result->from);
+ $this->assertEquals('NQ16 6MDL YQHG 9AE8 32UY 1GX1 MAPL MM7N L0KR', $result->fromAddress);
+ $this->assertEquals('4f61c06feeb7971af6997125fe40d629c01af92f', $result->to);
+ $this->assertEquals('NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F', $result->toAddress);
+ $this->assertEquals(2636710000, $result->value);
+ $this->assertEquals(0, $result->fee);
+ }
+
+ public function testGetTransactionByBlockHashAndIndexWhenNotFound()
+ {
+ $this->appendNextResponse('getTransaction/not-found.json');
+
+ $result = $this->client->getTransactionByBlockHashAndIndex('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', 5);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionByBlockHashAndIndex', $body['method']);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $body['params'][0]);
+ $this->assertEquals(5, $body['params'][1]);
+
+ $this->assertEquals(null, $result);
+ }
+
+ public function testGetTransactionByBlockNumberAndIndex()
+ {
+ $this->appendNextResponse('getTransaction/full-transaction.json');
+
+ $result = $this->client->getTransactionByBlockNumberAndIndex(11608, 0);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionByBlockNumberAndIndex', $body['method']);
+ $this->assertEquals(11608, $body['params'][0]);
+ $this->assertEquals(0, $body['params'][1]);
+
+ $this->assertInstanceOf(Transaction::class, $result);
+ $this->assertEquals('78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430', $result->hash);
+ $this->assertEquals(11608, $result->blockNumber);
+ $this->assertEquals(0, $result->transactionIndex);
+ $this->assertEquals('355b4fe2304a9c818b9f0c3c1aaaf4ad4f6a0279', $result->from);
+ $this->assertEquals('NQ16 6MDL YQHG 9AE8 32UY 1GX1 MAPL MM7N L0KR', $result->fromAddress);
+ $this->assertEquals('4f61c06feeb7971af6997125fe40d629c01af92f', $result->to);
+ $this->assertEquals('NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F', $result->toAddress);
+ $this->assertEquals(2636710000, $result->value);
+ $this->assertEquals(0, $result->fee);
+ }
+
+ public function testGetTransactionByBlockNumberAndIndexWhenNotFound()
+ {
+ $this->appendNextResponse('getTransaction/not-found.json');
+
+ $result = $this->client->getTransactionByBlockNumberAndIndex(11608, 0);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionByBlockNumberAndIndex', $body['method']);
+ $this->assertEquals(11608, $body['params'][0]);
+ $this->assertEquals(0, $body['params'][1]);
+
+ $this->assertEquals(null, $result);
+ }
+
+ public function testGetTransactionByHash()
+ {
+ $this->appendNextResponse('getTransaction/full-transaction.json');
+
+ $result = $this->client->getTransactionByHash('78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionByHash', $body['method']);
+ $this->assertEquals('78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430', $body['params'][0]);
+
+ $this->assertInstanceOf(Transaction::class, $result);
+ $this->assertEquals('78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430', $result->hash);
+ $this->assertEquals(11608, $result->blockNumber);
+ $this->assertEquals('355b4fe2304a9c818b9f0c3c1aaaf4ad4f6a0279', $result->from);
+ $this->assertEquals('NQ16 6MDL YQHG 9AE8 32UY 1GX1 MAPL MM7N L0KR', $result->fromAddress);
+ $this->assertEquals('4f61c06feeb7971af6997125fe40d629c01af92f', $result->to);
+ $this->assertEquals('NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F', $result->toAddress);
+ $this->assertEquals(2636710000, $result->value);
+ $this->assertEquals(0, $result->fee);
+ }
+
+ public function testGetTransactionByHashWhenNotFound()
+ {
+ $this->appendNextResponse('getTransaction/not-found.json');
+
+ $result = $this->client->getTransactionByHash('78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionByHash', $body['method']);
+ $this->assertEquals('78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430', $body['params'][0]);
+
+ $this->assertEquals(null, $result);
+ }
+
+ public function testGetTransactionByHashForContractCreation()
+ {
+ $this->appendNextResponse('getTransaction/contract-creation.json');
+
+ $result = $this->client->getTransactionByHash('539f6172b19f63be376ab7e962c368bb5f611deff6b159152c4cdf509f7daad2');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionByHash', $body['method']);
+ $this->assertEquals('539f6172b19f63be376ab7e962c368bb5f611deff6b159152c4cdf509f7daad2', $body['params'][0]);
+
+ $this->assertInstanceOf(Transaction::class, $result);
+ $this->assertEquals('539f6172b19f63be376ab7e962c368bb5f611deff6b159152c4cdf509f7daad2', $result->hash);
+ $this->assertEquals('96fef80f517f0b2704476dee48da147049b591e8f034e5bf93f1f6935fd51b85', $result->blockHash);
+ $this->assertEquals(1102500, $result->blockNumber);
+ $this->assertEquals(1590148157, $result->timestamp);
+ $this->assertEquals(7115, $result->confirmations);
+ $this->assertEquals('d62d519b3478c63bdd729cf2ccb863178060c64a', $result->from);
+ $this->assertEquals('NQ53 SQNM 36RL F333 PPBJ KKRC RE33 2X06 1HJA', $result->fromAddress);
+ $this->assertEquals('a22eaf17848130c9b370e42ff7d345680df245e1', $result->to);
+ $this->assertEquals('NQ87 L8PA X5U4 G4QC KCTG UGPY FLS5 D06Y 4HF1', $result->toAddress);
+ $this->assertEquals(5000000000, $result->value);
+ $this->assertEquals(0, $result->fee);
+ $this->assertEquals('d62d519b3478c63bdd729cf2ccb863178060c64af5ad55071730d3b9f05989481eefbda7324a44f8030c63b9444960db429081543939166f05116cebc37bd6975ac9f9e3bb43a5ab0b010010d2de', $result->data);
+ $this->assertEquals(1, $result->flags);
+ }
+
+ public function testGetTransactionReceipt()
+ {
+ $this->appendNextResponse('getTransactionReceipt/receipt.json');
+
+ $result = $this->client->getTransactionReceipt('fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionReceipt', $body['method']);
+ $this->assertEquals('fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e', $body['params'][0]);
+
+ $this->assertInstanceOf(TransactionReceipt::class, $result);
+ $this->assertEquals('fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e', $result->transactionHash);
+ $this->assertEquals(-1, $result->transactionIndex);
+ $this->assertEquals(11608, $result->blockNumber);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $result->blockHash);
+ $this->assertEquals(1523412456, $result->timestamp);
+ $this->assertEquals(718846, $result->confirmations);
+ }
+
+ public function testGetTransactionReceiptWhenNotFound()
+ {
+ $this->appendNextResponse('getTransactionReceipt/not-found.json');
+
+ $result = $this->client->getTransactionReceipt('unknown');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionReceipt', $body['method']);
+ $this->assertEquals('unknown', $body['params'][0]);
+
+ $this->assertNull($result);
+ }
+
+ public function testGetTransactionsByAddress()
+ {
+ $this->appendNextResponse('getTransactions/transactions-found.json');
+
+ $result = $this->client->getTransactionsByAddress('NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionsByAddress', $body['method']);
+ $this->assertEquals('NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F', $body['params'][0]);
+
+ $this->assertCount(3, $result);
+ $this->assertInstanceOf(Transaction::class, $result[0]);
+ $this->assertEquals('a514abb3ee4d3fbedf8a91156fb9ec4fdaf32f0d3d3da3c1dbc5fd1ee48db43e', $result[0]->hash);
+ $this->assertInstanceOf(Transaction::class, $result[1]);
+ $this->assertEquals('c8c0f586b11c7f39873c3de08610d63e8bec1ceaeba5e8a3bb13c709b2935f73', $result[1]->hash);
+ $this->assertInstanceOf(Transaction::class, $result[2]);
+ $this->assertEquals('fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e', $result[2]->hash);
+ }
+
+ public function testGetTransactionsByAddressWhenNoFound()
+ {
+ $this->appendNextResponse('getTransactions/no-transactions-found.json');
+
+ $result = $this->client->getTransactionsByAddress('NQ10 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getTransactionsByAddress', $body['method']);
+ $this->assertEquals('NQ10 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F', $body['params'][0]);
+
+ $this->assertEquals([], $result);
+ }
+
+ public function testGetMempoolContentHashesOnly()
+ {
+ $this->appendNextResponse('mempoolContent/hashes-only.json');
+
+ $result = $this->client->getMempoolContent();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('mempoolContent', $body['method']);
+ $this->assertEquals(false, $body['params'][0]);
+
+ $this->assertCount(3, $result);
+ $this->assertIsString($result[0]);
+ $this->assertEquals('5bb722c2afe25c18ba33d453b3ac2c90ac278c595cc92f6188c8b699e8fb006a', $result[0]);
+ $this->assertIsString($result[1]);
+ $this->assertEquals('f59a30e0a7e3348ef569225db1f4c29026aeac4350f8c6e751f669eddce0c718', $result[1]);
+ $this->assertIsString($result[2]);
+ $this->assertEquals('9cd9c1d0ffcaebfcfe86bc2ae73b4e82a488de99c8e3faef92b05432bb94519c', $result[2]);
+ }
+
+ public function testGetMempoolContentFullTransactions()
+ {
+ $this->appendNextResponse('mempoolContent/full-transactions.json');
+
+ $result = $this->client->getMempoolContent(true);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('mempoolContent', $body['method']);
+ $this->assertEquals(true, $body['params'][0]);
+
+ $this->assertCount(3, $result);
+ $this->assertInstanceOf(Transaction::class, $result[0]);
+ $this->assertEquals('5bb722c2afe25c18ba33d453b3ac2c90ac278c595cc92f6188c8b699e8fb006a', $result[0]->hash);
+ $this->assertInstanceOf(Transaction::class, $result[1]);
+ $this->assertEquals('f59a30e0a7e3348ef569225db1f4c29026aeac4350f8c6e751f669eddce0c718', $result[1]->hash);
+ $this->assertInstanceOf(Transaction::class, $result[2]);
+ $this->assertEquals('9cd9c1d0ffcaebfcfe86bc2ae73b4e82a488de99c8e3faef92b05432bb94519c', $result[2]->hash);
+ }
+
+ public function testGetMempoolWhenFull()
+ {
+ $this->appendNextResponse('mempool/mempool.json');
+
+ $result = $this->client->getMempool();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('mempool', $body['method']);
+
+ $this->assertInstanceOf(Mempool::class, $result);
+ $this->assertEquals(3, $result->total);
+ $this->assertEquals([1], $result->buckets);
+ $this->assertEquals(3, $result->transactionsPerBucket[1]);
+ }
+
+ public function testGetMempoolWhenEmpty()
+ {
+ $this->appendNextResponse('mempool/mempool-empty.json');
+
+ $result = $this->client->getMempool();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('mempool', $body['method']);
+
+ $this->assertInstanceOf(Mempool::class, $result);
+ $this->assertEquals(0, $result->total);
+ $this->assertEquals([], $result->buckets);
+ $this->assertEquals([], $result->transactionsPerBucket);
+ }
+
+ public function testGetMinFeePerByte()
+ {
+ $this->appendNextResponse('minFeePerByte/fee.json');
+
+ $result = $this->client->getMinFeePerByte();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('minFeePerByte', $body['method']);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(0, $result);
+ }
+
+ public function testSetMinFeePerByte()
+ {
+ $this->appendNextResponse('minFeePerByte/fee.json');
+
+ $result = $this->client->setMinFeePerByte(0);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('minFeePerByte', $body['method']);
+ $this->assertEquals(0, $body['params'][0]);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(0, $result);
+ }
+
+ public function testGetMiningState()
+ {
+ $this->appendNextResponse('miningState/mining.json');
+
+ $result = $this->client->getMiningState();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('mining', $body['method']);
+
+ $this->assertIsBool($result);
+ $this->assertEquals(false, $result);
+ }
+
+ public function testSetMiningState()
+ {
+ $this->appendNextResponse('miningState/mining.json');
+
+ $result = $this->client->setMiningState(false);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('mining', $body['method']);
+ $this->assertEquals(false, $body['params'][0]);
+
+ $this->assertIsBool($result);
+ $this->assertEquals(false, $result);
+ }
+
+ public function testGetHashrate()
+ {
+ $this->appendNextResponse('hashrate/hashrate.json');
+
+ $result = $this->client->getHashrate();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('hashrate', $body['method']);
+
+ $this->assertIsFloat($result);
+ $this->assertEquals(52982.2731, $result);
+ }
+
+ public function testGetMinerThreads()
+ {
+ $this->appendNextResponse('minerThreads/threads.json');
+
+ $result = $this->client->getMinerThreads();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('minerThreads', $body['method']);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(2, $result);
+ }
+
+ public function testSetMinerThreads()
+ {
+ $this->appendNextResponse('minerThreads/threads.json');
+
+ $result = $this->client->setMinerThreads(2);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('minerThreads', $body['method']);
+ $this->assertEquals(2, $body['params'][0]);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(2, $result);
+ }
+
+ public function testGetMinerAddress()
+ {
+ $this->appendNextResponse('minerAddress/address.json');
+
+ $result = $this->client->getMinerAddress();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('minerAddress', $body['method']);
+
+ $this->assertIsString($result);
+ $this->assertEquals('NQ39 NY67 X0F0 UTQE 0YER 4JEU B67L UPP8 G0FM', $result);
+ }
+
+ public function testGetPool()
+ {
+ $this->appendNextResponse('pool/sushipool.json');
+
+ $result = $this->client->getPool();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('pool', $body['method']);
+
+ $this->assertIsString($result);
+ $this->assertEquals('us.sushipool.com:443', $result);
+ }
+
+ public function testSetPool()
+ {
+ $this->appendNextResponse('pool/sushipool.json');
+
+ $result = $this->client->setPool('us.sushipool.com:443');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('pool', $body['method']);
+ $this->assertEquals('us.sushipool.com:443', $body['params'][0]);
+
+ $this->assertIsString($result);
+ $this->assertEquals('us.sushipool.com:443', $result);
+ }
+
+ public function testGetPoolWhenNoPool()
+ {
+ $this->appendNextResponse('pool/no-pool.json');
+
+ $result = $this->client->getPool();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('pool', $body['method']);
+
+ $this->assertEquals(null, $result);
+ }
+
+ public function testGetPoolConnectionState()
+ {
+ $this->appendNextResponse('pool/connection-state.json');
+
+ $result = $this->client->getPoolConnectionState();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('poolConnectionState', $body['method']);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(PoolConnectionState::Closed, $result);
+ }
+
+ public function testGetPoolConfirmedBalance()
+ {
+ $this->appendNextResponse('pool/confirmed-balance.json');
+
+ $result = $this->client->getPoolConfirmedBalance();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('poolConfirmedBalance', $body['method']);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(12000, $result);
+ }
+
+ public function testGetWork()
+ {
+ $this->appendNextResponse('getWork/work.json');
+
+ $result = $this->client->getWork();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getWork', $body['method']);
+
+ $this->assertEquals('00015a7d47ddf5152a7d06a14ea291831c3fc7af20b88240c5ae839683021bcee3e279877b3de0da8ce8878bf225f6782a2663eff9a03478c15ba839fde9f1dc3dd9e5f0cd4dbc96a30130de130eb52d8160e9197e2ccf435d8d24a09b518a5e05da87a8658ed8c02531f66a7d31757b08c88d283654ed477e5e2fec21a7ca8449241e00d620000dc2fa5e763bda00000000', $result['data']);
+ $this->assertEquals('11fad9806b8b4167517c162fa113c09606b44d24f8020804a0f756db085546ff585adfdedad9085d36527a8485b497728446c35b9b6c3db263c07dd0a1f487b1639aa37ff60ba3cf6ed8ab5146fee50a23ebd84ea37dca8c49b31e57d05c9e6c57f09a3b282b71ec2be66c1bc8268b5326bb222b11a0d0a4acd2a93c9e8a8713fe4383e9d5df3b1bf008c535281086b2bcc20e494393aea1475a5c3f13673de2cf7314d201b7cc7f01e0e6f0e07dd9249dc598f4e5ee8801f50000000000', $result['suffix']);
+ $this->assertEquals(503371296, $result['target']);
+ $this->assertEquals('nimiq-argon2', $result['algorithm']);
+ }
+
+ public function testGetWorkWithOverride()
+ {
+ $this->appendNextResponse('getWork/work.json');
+
+ $result = $this->client->getWork('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', '');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getWork', $body['method']);
+ $this->assertEquals('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', $body['params'][0]);
+ $this->assertEquals('', $body['params'][1]);
+
+ $this->assertEquals('00015a7d47ddf5152a7d06a14ea291831c3fc7af20b88240c5ae839683021bcee3e279877b3de0da8ce8878bf225f6782a2663eff9a03478c15ba839fde9f1dc3dd9e5f0cd4dbc96a30130de130eb52d8160e9197e2ccf435d8d24a09b518a5e05da87a8658ed8c02531f66a7d31757b08c88d283654ed477e5e2fec21a7ca8449241e00d620000dc2fa5e763bda00000000', $result['data']);
+ $this->assertEquals('11fad9806b8b4167517c162fa113c09606b44d24f8020804a0f756db085546ff585adfdedad9085d36527a8485b497728446c35b9b6c3db263c07dd0a1f487b1639aa37ff60ba3cf6ed8ab5146fee50a23ebd84ea37dca8c49b31e57d05c9e6c57f09a3b282b71ec2be66c1bc8268b5326bb222b11a0d0a4acd2a93c9e8a8713fe4383e9d5df3b1bf008c535281086b2bcc20e494393aea1475a5c3f13673de2cf7314d201b7cc7f01e0e6f0e07dd9249dc598f4e5ee8801f50000000000', $result['suffix']);
+ $this->assertEquals(503371296, $result['target']);
+ $this->assertEquals('nimiq-argon2', $result['algorithm']);
+ }
+
+ public function testGetBlockTemplate()
+ {
+ $this->appendNextResponse('getWork/block-template.json');
+
+ $result = $this->client->getBlockTemplate();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockTemplate', $body['method']);
+
+ $this->assertEquals(901883, $result['header']['height']);
+ $this->assertEquals(503371226, $result['target']);
+ $this->assertEquals('17e250f1977ae85bdbe09468efef83587885419ee1074ddae54d3fb5a96e1f54', $result['body']['hash']);
+ }
+
+ public function testGetBlockTemplateWithOverride()
+ {
+ $this->appendNextResponse('getWork/block-template.json');
+
+ $result = $this->client->getBlockTemplate('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', '');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockTemplate', $body['method']);
+ $this->assertEquals('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', $body['params'][0]);
+ $this->assertEquals('', $body['params'][1]);
+
+ $this->assertEquals(901883, $result['header']['height']);
+ $this->assertEquals(503371226, $result['target']);
+ $this->assertEquals('17e250f1977ae85bdbe09468efef83587885419ee1074ddae54d3fb5a96e1f54', $result['body']['hash']);
+ }
+
+ public function testSubmitBlock()
+ {
+ $this->appendNextResponse('submitBlock/submit.json');
+
+ $blockHex = '0001000000000000000000000000000000000000000000'
+ . '00000000000000000000000000000000000000000000000000000000000000000000000000000000'
+ . '000000f6ba2bbf7e1478a209057000471d73fbdc28df0b717747d929cfde829c4120f62e02da3d16'
+ . '2e20fa982029dbde9cc20f6b431ab05df1764f34af4c62a4f2b33f1f010000000000015ac3185f00'
+ . '0134990001000000000000000000000000000000000000000007546573744e657400000000';
+
+ $this->client->submitBlock($blockHex);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('submitBlock', $body['method']);
+ $this->assertEquals($blockHex, $body['params'][0]);
+ }
+
+ public function testGetAccounts()
+ {
+ $this->appendNextResponse('accounts/accounts.json');
+
+ $result = $this->client->getAccounts();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('accounts', $body['method']);
+
+ $this->assertCount(3, $result);
+ $this->assertInstanceOf(Account::class, $result[0]);
+ $this->assertEquals('NQ33 Y4JH 0UTN 10DX 88FM 5MJB VHTM RGFU 4219', $result[0]->address);
+ $this->assertEquals(AccountType::Basic, $result[0]->type);
+
+ $this->assertInstanceOf(Account::class, $result[1]);
+ $this->assertEquals('NQ09 VF5Y 1PKV MRM4 5LE1 55KV P6R2 GXYJ XYQF', $result[1]->address);
+ $this->assertEquals(AccountType::Vesting, $result[1]->type);
+ $this->assertEquals('NQ62 YLSA NUK5 L3J8 QHAC RFSC KHGV YPT8 Y6H2', $result[1]->ownerAddress);
+
+ $this->assertInstanceOf(Account::class, $result[2]);
+ $this->assertEquals('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', $result[2]->address);
+ $this->assertEquals(AccountType::Htlc, $result[2]->type);
+ $this->assertEquals('NQ53 SQNM 36RL F333 PPBJ KKRC RE33 2X06 1HJA', $result[2]->senderAddress);
+ }
+
+ public function testCreateAccount()
+ {
+ $this->appendNextResponse('createAccount/new-account.json');
+
+ $result = $this->client->createAccount();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('createAccount', $body['method']);
+
+ $this->assertInstanceOf(Wallet::class, $result);
+ $this->assertEquals('b6edcc7924af5a05af6087959c7233ec2cf1a5db', $result->id);
+ $this->assertEquals('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', $result->address);
+ $this->assertEquals('4f6d35cc47b77bf696b6cce72217e52edff972855bd17396b004a8453b020747', $result->publicKey);
+ }
+
+ public function testGetBalance()
+ {
+ $this->appendNextResponse('getBalance/balance.json');
+
+ $result = $this->client->getBalance('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBalance', $body['method']);
+ $this->assertEquals('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', $body['params'][0]);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(1200000, $result);
+ }
+
+ public function testGetAccountForBasicAccount()
+ {
+ $this->appendNextResponse('getAccount/basic.json');
+
+ $result = $this->client->getAccount('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getAccount', $body['method']);
+ $this->assertEquals('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', $body['params'][0]);
+
+ $this->assertInstanceOf(Account::class, $result);
+ $this->assertEquals('b6edcc7924af5a05af6087959c7233ec2cf1a5db', $result->id);
+ $this->assertEquals('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', $result->address);
+ $this->assertEquals(1200000, $result->balance);
+ $this->assertEquals(AccountType::Basic, $result->type);
+ }
+
+ public function testGetAccountForVestingContract()
+ {
+ $this->appendNextResponse('getAccount/vesting.json');
+
+ $result = $this->client->getAccount('NQ09 VF5Y 1PKV MRM4 5LE1 55KV P6R2 GXYJ XYQF');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getAccount', $body['method']);
+ $this->assertEquals('NQ09 VF5Y 1PKV MRM4 5LE1 55KV P6R2 GXYJ XYQF', $body['params'][0]);
+
+ $this->assertInstanceOf(Account::class, $result);
+ $this->assertEquals('ebcbf0de7dae6a42d1c12967db9b2287bf2f7f0f', $result->id);
+ $this->assertEquals('NQ09 VF5Y 1PKV MRM4 5LE1 55KV P6R2 GXYJ XYQF', $result->address);
+ $this->assertEquals(52500000000000, $result->balance);
+ $this->assertEquals(AccountType::Vesting, $result->type);
+ $this->assertEquals('fd34ab7265a0e48c454ccbf4c9c61dfdf68f9a22', $result->owner);
+ $this->assertEquals('NQ62 YLSA NUK5 L3J8 QHAC RFSC KHGV YPT8 Y6H2', $result->ownerAddress);
+ $this->assertEquals(1, $result->vestingStart);
+ $this->assertEquals(259200, $result->vestingStepBlocks);
+ $this->assertEquals(2625000000000, $result->vestingStepAmount);
+ $this->assertEquals(52500000000000, $result->vestingTotalAmount);
+ }
+
+ public function testGetAccountForHashedTimeLockedContract()
+ {
+ $this->appendNextResponse('getAccount/htlc.json');
+
+ $result = $this->client->getAccount('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getAccount', $body['method']);
+ $this->assertEquals('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', $body['params'][0]);
+
+ $this->assertInstanceOf(Account::class, $result);
+ $this->assertEquals('4974636bd6d34d52b7d4a2ee4425dc2be72a2b4e', $result->id);
+ $this->assertEquals('NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET', $result->address);
+ $this->assertEquals(1000000000, $result->balance);
+ $this->assertEquals(AccountType::Htlc, $result->type);
+ $this->assertEquals('d62d519b3478c63bdd729cf2ccb863178060c64a', $result->sender);
+ $this->assertEquals('NQ53 SQNM 36RL F333 PPBJ KKRC RE33 2X06 1HJA', $result->senderAddress);
+ $this->assertEquals('f5ad55071730d3b9f05989481eefbda7324a44f8', $result->recipient);
+ $this->assertEquals('NQ41 XNNM A1QP 639T KU2R H541 VTVV LUR4 LH7Q', $result->recipientAddress);
+ $this->assertEquals('df331b3c8f8a889703092ea05503779058b7f44e71bc57176378adde424ce922', $result->hashRoot);
+ $this->assertEquals(1, $result->hashAlgorithm);
+ $this->assertEquals(1, $result->hashCount);
+ $this->assertEquals(1105605, $result->timeout);
+ $this->assertEquals(1000000000, $result->totalAmount);
+ }
+
+ public function testGetBlockNumber()
+ {
+ $this->appendNextResponse('blockNumber/block-number.json');
+
+ $result = $this->client->getBlockNumber();
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('blockNumber', $body['method']);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(748883, $result);
+ }
+
+ public function testGetBlockTransactionCountByHash()
+ {
+ $this->appendNextResponse('blockTransactionCount/found.json');
+
+ $result = $this->client->getBlockTransactionCountByHash('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockTransactionCountByHash', $body['method']);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $body['params'][0]);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(2, $result);
+ }
+
+ public function testGetBlockTransactionCountByHashWhenNotFound()
+ {
+ $this->appendNextResponse('blockTransactionCount/not-found.json');
+
+ $result = $this->client->getBlockTransactionCountByHash('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockTransactionCountByHash', $body['method']);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $body['params'][0]);
+
+ $this->assertEquals(null, $result);
+ }
+
+ public function testGetBlockTransactionCountByNumber()
+ {
+ $this->appendNextResponse('blockTransactionCount/found.json');
+
+ $result = $this->client->getBlockTransactionCountByNumber(11608);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockTransactionCountByNumber', $body['method']);
+ $this->assertEquals(11608, $body['params'][0]);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(2, $result);
+ }
+
+ public function testGetBlockTransactionCountByNumberWhenNotFound()
+ {
+ $this->appendNextResponse('blockTransactionCount/not-found.json');
+
+ $result = $this->client->getBlockTransactionCountByNumber(11608);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockTransactionCountByNumber', $body['method']);
+ $this->assertEquals(11608, $body['params'][0]);
+
+ $this->assertEquals(null, $result);
+ }
+
+ public function testGetBlockByHash()
+ {
+ $this->appendNextResponse('getBlock/block-found.json');
+
+ $result = $this->client->getBlockByHash('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockByHash', $body['method']);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $body['params'][0]);
+ $this->assertEquals(false, $body['params'][1]);
+
+ $this->assertInstanceOf(Block::class, $result);
+ $this->assertEquals(11608, $result->number);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $result->hash);
+ $this->assertEquals(739224, $result->confirmations);
+ $this->assertEquals([
+ '78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430',
+ 'fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e',
+ ], $result->transactions);
+ }
+
+ public function testGetBlockByHashWithTransactions()
+ {
+ $this->appendNextResponse('getBlock/block-with-transactions.json');
+
+ $result = $this->client->getBlockByHash('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', true);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockByHash', $body['method']);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $body['params'][0]);
+ $this->assertEquals(true, $body['params'][1]);
+
+ $this->assertInstanceOf(Block::class, $result);
+ $this->assertEquals(11608, $result->number);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $result->hash);
+ $this->assertEquals(739501, $result->confirmations);
+
+ $this->assertCount(2, $result->transactions);
+ $this->assertInstanceOf(Transaction::class, $result->transactions[0]);
+ $this->assertInstanceOf(Transaction::class, $result->transactions[1]);
+ }
+
+ public function testGetBlockByHashNotFound()
+ {
+ $this->appendNextResponse('getBlock/block-not-found.json');
+
+ $result = $this->client->getBlockByHash('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockByHash', $body['method']);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $body['params'][0]);
+ $this->assertEquals(false, $body['params'][1]);
+
+ $this->assertNull($result);
+ }
+
+ public function testGetBlockByNumber()
+ {
+ $this->appendNextResponse('getBlock/block-found.json');
+
+ $result = $this->client->getBlockByNumber(11608);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockByNumber', $body['method']);
+ $this->assertEquals(11608, $body['params'][0]);
+ $this->assertEquals(false, $body['params'][1]);
+
+ $this->assertInstanceOf(Block::class, $result);
+ $this->assertEquals(11608, $result->number);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $result->hash);
+ $this->assertEquals(739224, $result->confirmations);
+ $this->assertEquals([
+ '78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430',
+ 'fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e',
+ ], $result->transactions);
+ }
+
+ public function testGetBlockByNumberWithTransactions()
+ {
+ $this->appendNextResponse('getBlock/block-with-transactions.json');
+
+ $result = $this->client->getBlockByNumber(11608, true);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockByNumber', $body['method']);
+ $this->assertEquals(11608, $body['params'][0]);
+ $this->assertEquals(true, $body['params'][1]);
+
+ $this->assertInstanceOf(Block::class, $result);
+ $this->assertEquals(11608, $result->number);
+ $this->assertEquals('bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786', $result->hash);
+ $this->assertEquals(739501, $result->confirmations);
+
+ $this->assertCount(2, $result->transactions);
+ $this->assertInstanceOf(Transaction::class, $result->transactions[0]);
+ $this->assertInstanceOf(Transaction::class, $result->transactions[1]);
+ }
+
+ public function testGetBlockByNumberNotFound()
+ {
+ $this->appendNextResponse('getBlock/block-not-found.json');
+
+ $result = $this->client->getBlockByNumber(11608);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('getBlockByNumber', $body['method']);
+ $this->assertEquals(11608, $body['params'][0]);
+ $this->assertEquals(false, $body['params'][1]);
+
+ $this->assertNull($result);
+ }
+
+ public function testGetConstant()
+ {
+ $this->appendNextResponse('constant/constant.json');
+
+ $result = $this->client->getConstant('BaseConsensus.MAX_ATTEMPTS_TO_FETCH');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('constant', $body['method']);
+ $this->assertEquals('BaseConsensus.MAX_ATTEMPTS_TO_FETCH', $body['params'][0]);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(5, $result);
+ }
+
+ public function testSetConstant()
+ {
+ $this->appendNextResponse('constant/constant.json');
+
+ $result = $this->client->setConstant('BaseConsensus.MAX_ATTEMPTS_TO_FETCH', 10);
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('constant', $body['method']);
+ $this->assertEquals('BaseConsensus.MAX_ATTEMPTS_TO_FETCH', $body['params'][0]);
+ $this->assertEquals(10, $body['params'][1]);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(5, $result);
+ }
+
+ public function testResetConstant()
+ {
+ $this->appendNextResponse('constant/constant.json');
+
+ $result = $this->client->resetConstant('BaseConsensus.MAX_ATTEMPTS_TO_FETCH');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('constant', $body['method']);
+ $this->assertEquals('BaseConsensus.MAX_ATTEMPTS_TO_FETCH', $body['params'][0]);
+ $this->assertEquals('reset', $body['params'][1]);
+
+ $this->assertIsInt($result);
+ $this->assertEquals(5, $result);
+ }
+
+ public function testSetLogLevel()
+ {
+ $this->appendNextResponse('log/log.json');
+
+ $result = $this->client->setLogLevel('*', 'verbose');
+
+ $body = $this->getLastRequestBody();
+ $this->assertEquals('log', $body['method']);
+ $this->assertEquals('*', $body['params'][0]);
+ $this->assertEquals('verbose', $body['params'][1]);
+
+ $this->assertTrue($result);
+ }
+
+ private function appendNextResponse($fixture)
+ {
+ $jsonResponse = file_get_contents(dirname(__FILE__) . '/fixtures/' . $fixture);
+
+ $this->mock->append(new \GuzzleHttp\Psr7\Response(200, [], $jsonResponse));
+ }
+
+ private function getLastRequestBody()
+ {
+ $request = $this->mock->getLastRequest();
+
+ return json_decode($request->getBody()->getContents(), true);
+ }
+}
diff --git a/tests/ResponseTest.php b/tests/ResponseTest.php
new file mode 100644
index 0000000..5db5a4b
--- /dev/null
+++ b/tests/ResponseTest.php
@@ -0,0 +1,64 @@
+assertTrue($response->hasResult());
+ $this->assertEquals(487233, $response->getResult());
+ }
+
+ public function testHasErrorIsFalseForSuccessfulResponse()
+ {
+ $mockResponse = new \GuzzleHttp\Psr7\Response(200, [], '{"jsonrpc":"2.0","result":487233,"id":1}');
+ $response = new NimiqResponse($mockResponse);
+
+ $this->assertFalse($response->hasError());
+ }
+
+ public function testErrorCanBeRetrievedForErrorResponse()
+ {
+ $mockResponse = new \GuzzleHttp\Psr7\Response(200, [], '{"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found"},"id":1}');
+ $response = new NimiqResponse($mockResponse);
+
+ $this->assertTrue($response->hasError());
+ $this->assertEquals([
+ 'code' => -32601,
+ 'message' => 'Method not found',
+ ], $response->getError());
+ }
+
+ public function testHasResultIsFalseForSuccessfulResponse()
+ {
+ $mockResponse = new \GuzzleHttp\Psr7\Response(200, [], '{"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found"},"id":1}');
+ $response = new NimiqResponse($mockResponse);
+
+ $this->assertFalse($response->hasResult());
+ }
+
+ public function testOriginalResponseObjectCanBeRetrieved()
+ {
+ $mockResponse = new \GuzzleHttp\Psr7\Response(200, [], '{"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found"},"id":1}');
+ $response = new NimiqResponse($mockResponse);
+
+ $this->assertEquals('{"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found"},"id":1}', $response->getResponse()->getBody()->__toString());
+ }
+
+ public function testResponseCanReturnTheRpcId()
+ {
+ $mockResponse = new \GuzzleHttp\Psr7\Response(200, [], '{"jsonrpc":"2.0","result":487233,"id":1}');
+ $response = new NimiqResponse($mockResponse);
+
+ $this->assertEquals(1, $response->getId());
+ }
+}
diff --git a/tests/fixtures/accounts/accounts.json b/tests/fixtures/accounts/accounts.json
new file mode 100644
index 0000000..39fee18
--- /dev/null
+++ b/tests/fixtures/accounts/accounts.json
@@ -0,0 +1,39 @@
+{
+ "jsonrpc": "2.0",
+ "result": [
+ {
+ "id": "f925107376081be421f52d64bec775cc1fc20829",
+ "address": "NQ33 Y4JH 0UTN 10DX 88FM 5MJB VHTM RGFU 4219",
+ "balance": 0,
+ "type": 0
+ },
+ {
+ "id": "ebcbf0de7dae6a42d1c12967db9b2287bf2f7f0f",
+ "address": "NQ09 VF5Y 1PKV MRM4 5LE1 55KV P6R2 GXYJ XYQF",
+ "balance": 52500000000000,
+ "type": 1,
+ "owner": "fd34ab7265a0e48c454ccbf4c9c61dfdf68f9a22",
+ "ownerAddress": "NQ62 YLSA NUK5 L3J8 QHAC RFSC KHGV YPT8 Y6H2",
+ "vestingStart": 1,
+ "vestingStepBlocks": 259200,
+ "vestingStepAmount": 2625000000000,
+ "vestingTotalAmount": 52500000000000
+ },
+ {
+ "id": "4974636bd6d34d52b7d4a2ee4425dc2be72a2b4e",
+ "address": "NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET",
+ "balance": 1000000000,
+ "type": 2,
+ "sender": "d62d519b3478c63bdd729cf2ccb863178060c64a",
+ "senderAddress": "NQ53 SQNM 36RL F333 PPBJ KKRC RE33 2X06 1HJA",
+ "recipient": "f5ad55071730d3b9f05989481eefbda7324a44f8",
+ "recipientAddress": "NQ41 XNNM A1QP 639T KU2R H541 VTVV LUR4 LH7Q",
+ "hashRoot": "df331b3c8f8a889703092ea05503779058b7f44e71bc57176378adde424ce922",
+ "hashAlgorithm": 1,
+ "hashCount": 1,
+ "timeout": 1105605,
+ "totalAmount": 1000000000
+ }
+ ],
+ "id": 1
+}
diff --git a/tests/fixtures/blockNumber/block-number.json b/tests/fixtures/blockNumber/block-number.json
new file mode 100644
index 0000000..1eb92dc
--- /dev/null
+++ b/tests/fixtures/blockNumber/block-number.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": 748883,
+ "id": 1
+}
diff --git a/tests/fixtures/blockTransactionCount/found.json b/tests/fixtures/blockTransactionCount/found.json
new file mode 100644
index 0000000..49eab50
--- /dev/null
+++ b/tests/fixtures/blockTransactionCount/found.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": 2,
+ "id": 1
+}
diff --git a/tests/fixtures/blockTransactionCount/not-found.json b/tests/fixtures/blockTransactionCount/not-found.json
new file mode 100644
index 0000000..2fbb1ed
--- /dev/null
+++ b/tests/fixtures/blockTransactionCount/not-found.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": null,
+ "id": 1
+}
diff --git a/tests/fixtures/consensus/syncing.json b/tests/fixtures/consensus/syncing.json
new file mode 100644
index 0000000..7bb5582
--- /dev/null
+++ b/tests/fixtures/consensus/syncing.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": "syncing",
+ "id": 1
+}
diff --git a/tests/fixtures/constant/constant.json b/tests/fixtures/constant/constant.json
new file mode 100644
index 0000000..c44a2f1
--- /dev/null
+++ b/tests/fixtures/constant/constant.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": 5,
+ "id": 1
+}
diff --git a/tests/fixtures/createAccount/new-account.json b/tests/fixtures/createAccount/new-account.json
new file mode 100644
index 0000000..f45c3f4
--- /dev/null
+++ b/tests/fixtures/createAccount/new-account.json
@@ -0,0 +1,9 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "id": "b6edcc7924af5a05af6087959c7233ec2cf1a5db",
+ "address": "NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET",
+ "publicKey": "4f6d35cc47b77bf696b6cce72217e52edff972855bd17396b004a8453b020747"
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/createRawTransaction/basic.json b/tests/fixtures/createRawTransaction/basic.json
new file mode 100644
index 0000000..a81e350
--- /dev/null
+++ b/tests/fixtures/createRawTransaction/basic.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": "00c3c0d1af80b84c3b3de4e3d79d5c8cc950e044098c969953d68bf9cee68d7b53305dbaac7514a06dae935e40d599caf1bd8a243c00000000000186a00000000000000001000af84c01239b16cee089836c2af5c7b1dbb22cdc0b4864349f7f3805909aa8cf24e4c1ff0461832e86f3624778a867d5f2ba318f92918ada7ae28d70d40c4ef1d6413802",
+ "id": 1
+}
diff --git a/tests/fixtures/getAccount/basic.json b/tests/fixtures/getAccount/basic.json
new file mode 100644
index 0000000..3b3934e
--- /dev/null
+++ b/tests/fixtures/getAccount/basic.json
@@ -0,0 +1,10 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "id": "b6edcc7924af5a05af6087959c7233ec2cf1a5db",
+ "address": "NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET",
+ "balance": 1200000,
+ "type": 0
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getAccount/htlc.json b/tests/fixtures/getAccount/htlc.json
new file mode 100644
index 0000000..9ac0cea
--- /dev/null
+++ b/tests/fixtures/getAccount/htlc.json
@@ -0,0 +1,19 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "id": "4974636bd6d34d52b7d4a2ee4425dc2be72a2b4e",
+ "address": "NQ46 NTNU QX94 MVD0 BBT0 GXAR QUHK VGNF 39ET",
+ "balance": 1000000000,
+ "type": 2,
+ "sender": "d62d519b3478c63bdd729cf2ccb863178060c64a",
+ "senderAddress": "NQ53 SQNM 36RL F333 PPBJ KKRC RE33 2X06 1HJA",
+ "recipient": "f5ad55071730d3b9f05989481eefbda7324a44f8",
+ "recipientAddress": "NQ41 XNNM A1QP 639T KU2R H541 VTVV LUR4 LH7Q",
+ "hashRoot": "df331b3c8f8a889703092ea05503779058b7f44e71bc57176378adde424ce922",
+ "hashAlgorithm": 1,
+ "hashCount": 1,
+ "timeout": 1105605,
+ "totalAmount": 1000000000
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getAccount/vesting.json b/tests/fixtures/getAccount/vesting.json
new file mode 100644
index 0000000..e4d6651
--- /dev/null
+++ b/tests/fixtures/getAccount/vesting.json
@@ -0,0 +1,16 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "id": "ebcbf0de7dae6a42d1c12967db9b2287bf2f7f0f",
+ "address": "NQ09 VF5Y 1PKV MRM4 5LE1 55KV P6R2 GXYJ XYQF",
+ "balance": 52500000000000,
+ "type": 1,
+ "owner": "fd34ab7265a0e48c454ccbf4c9c61dfdf68f9a22",
+ "ownerAddress": "NQ62 YLSA NUK5 L3J8 QHAC RFSC KHGV YPT8 Y6H2",
+ "vestingStart": 1,
+ "vestingStepBlocks": 259200,
+ "vestingStepAmount": 2625000000000,
+ "vestingTotalAmount": 52500000000000
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getBalance/balance.json b/tests/fixtures/getBalance/balance.json
new file mode 100644
index 0000000..3331a35
--- /dev/null
+++ b/tests/fixtures/getBalance/balance.json
@@ -0,0 +1,5 @@
+{
+ "id": 1,
+ "jsonrpc": "2.0",
+ "result": 1200000
+}
diff --git a/tests/fixtures/getBlock/block-found.json b/tests/fixtures/getBlock/block-found.json
new file mode 100644
index 0000000..df8497d
--- /dev/null
+++ b/tests/fixtures/getBlock/block-found.json
@@ -0,0 +1,24 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "number": 11608,
+ "hash": "bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786",
+ "pow": "00000015f5b8c5315e001ad23b6d0aa5a1d201c21e523c19d3a4844705997ed2",
+ "parentHash": "4772b0a8da82a15590f73886fd763164246f982652c16355da10d99fbcb844ac",
+ "nonce": 1713217,
+ "bodyHash": "703fb0545f0361407599134cc8277bab69d0caeccedfc54ee8559ec4b061be75",
+ "accountsHash": "2d9395ed6877c85db1aa6a4868b9190a515c3f0c6e7a95e4621f93ac5d55b24b",
+ "difficulty": "2953.5300598756",
+ "timestamp": 1523412456,
+ "confirmations": 739224,
+ "miner": "638ea89b26961884ff3b1b4a5a65968c28be7599",
+ "minerAddress": "NQ94 CE7A H6R6 JQC8 9YRT 3D55 LRCN HGLB UVCR",
+ "extraData": "",
+ "size": 643,
+ "transactions": [
+ "78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430",
+ "fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e"
+ ]
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getBlock/block-not-found.json b/tests/fixtures/getBlock/block-not-found.json
new file mode 100644
index 0000000..2fbb1ed
--- /dev/null
+++ b/tests/fixtures/getBlock/block-not-found.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": null,
+ "id": 1
+}
diff --git a/tests/fixtures/getBlock/block-with-transactions.json b/tests/fixtures/getBlock/block-with-transactions.json
new file mode 100644
index 0000000..f5abae2
--- /dev/null
+++ b/tests/fixtures/getBlock/block-with-transactions.json
@@ -0,0 +1,54 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "number": 11608,
+ "hash": "bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786",
+ "pow": "00000015f5b8c5315e001ad23b6d0aa5a1d201c21e523c19d3a4844705997ed2",
+ "parentHash": "4772b0a8da82a15590f73886fd763164246f982652c16355da10d99fbcb844ac",
+ "nonce": 1713217,
+ "bodyHash": "703fb0545f0361407599134cc8277bab69d0caeccedfc54ee8559ec4b061be75",
+ "accountsHash": "2d9395ed6877c85db1aa6a4868b9190a515c3f0c6e7a95e4621f93ac5d55b24b",
+ "difficulty": "2953.5300598756",
+ "timestamp": 1523412456,
+ "confirmations": 739501,
+ "miner": "638ea89b26961884ff3b1b4a5a65968c28be7599",
+ "minerAddress": "NQ94 CE7A H6R6 JQC8 9YRT 3D55 LRCN HGLB UVCR",
+ "extraData": "",
+ "size": 643,
+ "transactions": [
+ {
+ "hash": "78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430",
+ "blockHash": "bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786",
+ "blockNumber": 11608,
+ "timestamp": 1523412456,
+ "confirmations": 739502,
+ "transactionIndex": 0,
+ "from": "355b4fe2304a9c818b9f0c3c1aaaf4ad4f6a0279",
+ "fromAddress": "NQ16 6MDL YQHG 9AE8 32UY 1GX1 MAPL MM7N L0KR",
+ "to": "4f61c06feeb7971af6997125fe40d629c01af92f",
+ "toAddress": "NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F",
+ "value": 2636710000,
+ "fee": 0,
+ "data": null,
+ "flags": 0
+ },
+ {
+ "hash": "fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e",
+ "blockHash": "bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786",
+ "blockNumber": 11608,
+ "timestamp": 1523412456,
+ "confirmations": 739502,
+ "transactionIndex": 1,
+ "from": "0e229e99c9af35f040fc38aa5f722a78ce88c15b",
+ "fromAddress": "NQ13 1QH9 V6E9 MUSY 0G7U 72M5 XUHA F378 HGAT",
+ "to": "4f61c06feeb7971af6997125fe40d629c01af92f",
+ "toAddress": "NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F",
+ "value": 2860228000,
+ "fee": 0,
+ "data": null,
+ "flags": 0
+ }
+ ]
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getRawTransactionInfo/basic-transaction.json b/tests/fixtures/getRawTransactionInfo/basic-transaction.json
new file mode 100644
index 0000000..cc9579d
--- /dev/null
+++ b/tests/fixtures/getRawTransactionInfo/basic-transaction.json
@@ -0,0 +1,18 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "hash": "7784f2f6eaa076fa5cf0e4d06311ad204b2f485de622231785451181e8129091",
+ "confirmations": 0,
+ "from": "b7cc7f01e0e6f0e07dd9249dc598f4e5ee8801f5",
+ "fromAddress": "NQ39 NY67 X0F0 UTQE 0YER 4JEU B67L UPP8 G0FM",
+ "to": "305dbaac7514a06dae935e40d599caf1bd8a243c",
+ "toAddress": "NQ16 61ET MB3M 2JG6 TBLK BR0D B6EA X6XQ L91U",
+ "value": 100000,
+ "fee": 1,
+ "data": null,
+ "flags": 0,
+ "valid": true,
+ "inMempool": false
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getTransaction/contract-creation.json b/tests/fixtures/getTransaction/contract-creation.json
new file mode 100644
index 0000000..bd33d9a
--- /dev/null
+++ b/tests/fixtures/getTransaction/contract-creation.json
@@ -0,0 +1,19 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "hash": "539f6172b19f63be376ab7e962c368bb5f611deff6b159152c4cdf509f7daad2",
+ "blockHash": "96fef80f517f0b2704476dee48da147049b591e8f034e5bf93f1f6935fd51b85",
+ "blockNumber": 1102500,
+ "timestamp": 1590148157,
+ "confirmations": 7115,
+ "from": "d62d519b3478c63bdd729cf2ccb863178060c64a",
+ "fromAddress": "NQ53 SQNM 36RL F333 PPBJ KKRC RE33 2X06 1HJA",
+ "to": "a22eaf17848130c9b370e42ff7d345680df245e1",
+ "toAddress": "NQ87 L8PA X5U4 G4QC KCTG UGPY FLS5 D06Y 4HF1",
+ "value": 5000000000,
+ "fee": 0,
+ "data": "d62d519b3478c63bdd729cf2ccb863178060c64af5ad55071730d3b9f05989481eefbda7324a44f8030c63b9444960db429081543939166f05116cebc37bd6975ac9f9e3bb43a5ab0b010010d2de",
+ "flags": 1
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getTransaction/full-transaction.json b/tests/fixtures/getTransaction/full-transaction.json
new file mode 100644
index 0000000..d104f6a
--- /dev/null
+++ b/tests/fixtures/getTransaction/full-transaction.json
@@ -0,0 +1,20 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "hash": "78957b87ab5546e11e9540ce5a37ebbf93a0ebd73c0ce05f137288f30ee9f430",
+ "blockHash": "bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786",
+ "blockNumber": 11608,
+ "timestamp": 1523412456,
+ "confirmations": 715571,
+ "transactionIndex": 0,
+ "from": "355b4fe2304a9c818b9f0c3c1aaaf4ad4f6a0279",
+ "fromAddress": "NQ16 6MDL YQHG 9AE8 32UY 1GX1 MAPL MM7N L0KR",
+ "to": "4f61c06feeb7971af6997125fe40d629c01af92f",
+ "toAddress": "NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F",
+ "value": 2636710000,
+ "fee": 0,
+ "data": null,
+ "flags": 0
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getTransaction/not-found.json b/tests/fixtures/getTransaction/not-found.json
new file mode 100644
index 0000000..2fbb1ed
--- /dev/null
+++ b/tests/fixtures/getTransaction/not-found.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": null,
+ "id": 1
+}
diff --git a/tests/fixtures/getTransactionReceipt/not-found.json b/tests/fixtures/getTransactionReceipt/not-found.json
new file mode 100644
index 0000000..2fbb1ed
--- /dev/null
+++ b/tests/fixtures/getTransactionReceipt/not-found.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": null,
+ "id": 1
+}
diff --git a/tests/fixtures/getTransactionReceipt/receipt.json b/tests/fixtures/getTransactionReceipt/receipt.json
new file mode 100644
index 0000000..41b9c7e
--- /dev/null
+++ b/tests/fixtures/getTransactionReceipt/receipt.json
@@ -0,0 +1,12 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "transactionHash": "fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e",
+ "transactionIndex": -1,
+ "blockNumber": 11608,
+ "blockHash": "bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786",
+ "confirmations": 718846,
+ "timestamp": 1523412456
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getTransactions/no-transactions-found.json b/tests/fixtures/getTransactions/no-transactions-found.json
new file mode 100644
index 0000000..1ae04ea
--- /dev/null
+++ b/tests/fixtures/getTransactions/no-transactions-found.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": [],
+ "id": 1
+}
diff --git a/tests/fixtures/getTransactions/transactions-found.json b/tests/fixtures/getTransactions/transactions-found.json
new file mode 100644
index 0000000..8c310d9
--- /dev/null
+++ b/tests/fixtures/getTransactions/transactions-found.json
@@ -0,0 +1,51 @@
+{
+ "jsonrpc": "2.0",
+ "result": [
+ {
+ "hash": "a514abb3ee4d3fbedf8a91156fb9ec4fdaf32f0d3d3da3c1dbc5fd1ee48db43e",
+ "blockHash": "c5c84b23dde619aff143c738884b2293aa1dd8bf6117a7375fa9ec824e410113",
+ "blockNumber": 14653,
+ "timestamp": 1523598270,
+ "confirmations": 716919,
+ "from": "0e229e99c9af35f040fc38aa5f722a78ce88c15b",
+ "fromAddress": "NQ13 1QH9 V6E9 MUSY 0G7U 72M5 XUHA F378 HGAT",
+ "to": "4f61c06feeb7971af6997125fe40d629c01af92f",
+ "toAddress": "NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F",
+ "value": 1317394000,
+ "fee": 0,
+ "data": null,
+ "flags": 0
+ },
+ {
+ "hash": "c8c0f586b11c7f39873c3de08610d63e8bec1ceaeba5e8a3bb13c709b2935f73",
+ "blockHash": "0de50c9c490b29cdaaf68a96dcf0a420a7bb441c63f87310485c5219b604a7d3",
+ "blockNumber": 13280,
+ "timestamp": 1523515965,
+ "confirmations": 718292,
+ "from": "0e229e99c9af35f040fc38aa5f722a78ce88c15b",
+ "fromAddress": "NQ13 1QH9 V6E9 MUSY 0G7U 72M5 XUHA F378 HGAT",
+ "to": "4f61c06feeb7971af6997125fe40d629c01af92f",
+ "toAddress": "NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F",
+ "value": 2635766000,
+ "fee": 0,
+ "data": null,
+ "flags": 0
+ },
+ {
+ "hash": "fd8e46ae55c5b8cd7cb086cf8d6c81f941a516d6148021d55f912fb2ca75cc8e",
+ "blockHash": "bc3945d22c9f6441409a6e539728534a4fc97859bda87333071fad9dad942786",
+ "blockNumber": 11608,
+ "timestamp": 1523412456,
+ "confirmations": 719964,
+ "from": "0e229e99c9af35f040fc38aa5f722a78ce88c15b",
+ "fromAddress": "NQ13 1QH9 V6E9 MUSY 0G7U 72M5 XUHA F378 HGAT",
+ "to": "4f61c06feeb7971af6997125fe40d629c01af92f",
+ "toAddress": "NQ05 9VGU 0TYE NXBH MVLR E4JY UG6N 5701 MX9F",
+ "value": 2860228000,
+ "fee": 0,
+ "data": null,
+ "flags": 0
+ }
+ ],
+ "id": 1
+}
diff --git a/tests/fixtures/getWork/block-template.json b/tests/fixtures/getWork/block-template.json
new file mode 100644
index 0000000..8172edc
--- /dev/null
+++ b/tests/fixtures/getWork/block-template.json
@@ -0,0 +1,28 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "header": {
+ "version": 1,
+ "prevHash": "b6d0644d171957dfc5e85ec36fcb4772a7783c6c47da23d0b7fe9ceb1a6b85f1",
+ "interlinkHash": "960b72c50828837782b92698555e23492e4f75018a2ba5dffea0b89df436e3b0",
+ "accountsHash": "78f442b1962bf9dd07e1b25bf4c42c59e3e40eec7fedf6853c579b6cc56330c1",
+ "nBits": 503371226,
+ "height": 901883
+ },
+ "interlink": "11ead9805a7d47ddf5152a7d06a14ea291831c3fc7af20b88240c5ae839683021bcee3e26b8b4167517c162fa113c09606b44d24f8020804a0f756db085546ff585adfdedad9085d36527a8485b497728446c35b9b6c3db263c07dd0a1f487b1639aa37ff60ba3cf6ed8ab5146fee50a23ebd84ea37dca8c49b31e57d05c9e6c57f09a3b282b71ec2be66c1bc8268b5326bb222b11a0d0a4acd2a93c9e8a8713fe4383e9d5df3b1bf008c535281086b2bcc20e494393aea1475a5c3f13673de2cf7314d2",
+ "target": 503371226,
+ "body": {
+ "hash": "17e250f1977ae85bdbe09468efef83587885419ee1074ddae54d3fb5a96e1f54",
+ "minerAddr": "b7cc7f01e0e6f0e07dd9249dc598f4e5ee8801f5",
+ "extraData": "",
+ "transactions": [
+ "009207144f80a4a479b6954c342ef61747c018d368b4bb86dcb70bfc19381e0c9323c5b9092959ee29b05394e184685e3ff7d3c2a60000000029f007a6000000000000008a000dc2fa0144eccc3af5be34553193aacd543b39b21a79d32c975a9e3f958a9516ff92f134f15ae5a70cadcfcf89d3ced84dd9569d04e40d6d138e9e504ed8e70f31a3d407"
+ ],
+ "merkleHashes": [
+ "6039a78b6be96bd0b539c6b2bf52fe6e5970571e0ee3afba798f701eee561ea2"
+ ],
+ "prunedAccounts": []
+ }
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/getWork/work.json b/tests/fixtures/getWork/work.json
new file mode 100644
index 0000000..16a74e3
--- /dev/null
+++ b/tests/fixtures/getWork/work.json
@@ -0,0 +1,10 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "data": "00015a7d47ddf5152a7d06a14ea291831c3fc7af20b88240c5ae839683021bcee3e279877b3de0da8ce8878bf225f6782a2663eff9a03478c15ba839fde9f1dc3dd9e5f0cd4dbc96a30130de130eb52d8160e9197e2ccf435d8d24a09b518a5e05da87a8658ed8c02531f66a7d31757b08c88d283654ed477e5e2fec21a7ca8449241e00d620000dc2fa5e763bda00000000",
+ "suffix": "11fad9806b8b4167517c162fa113c09606b44d24f8020804a0f756db085546ff585adfdedad9085d36527a8485b497728446c35b9b6c3db263c07dd0a1f487b1639aa37ff60ba3cf6ed8ab5146fee50a23ebd84ea37dca8c49b31e57d05c9e6c57f09a3b282b71ec2be66c1bc8268b5326bb222b11a0d0a4acd2a93c9e8a8713fe4383e9d5df3b1bf008c535281086b2bcc20e494393aea1475a5c3f13673de2cf7314d201b7cc7f01e0e6f0e07dd9249dc598f4e5ee8801f50000000000",
+ "target": 503371296,
+ "algorithm": "nimiq-argon2"
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/hashrate/hashrate.json b/tests/fixtures/hashrate/hashrate.json
new file mode 100644
index 0000000..2346dc1
--- /dev/null
+++ b/tests/fixtures/hashrate/hashrate.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": 52982.2731,
+ "id": 1
+}
diff --git a/tests/fixtures/log/log.json b/tests/fixtures/log/log.json
new file mode 100644
index 0000000..2f9668e
--- /dev/null
+++ b/tests/fixtures/log/log.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": true,
+ "id": 1
+}
diff --git a/tests/fixtures/mempool/mempool-empty.json b/tests/fixtures/mempool/mempool-empty.json
new file mode 100644
index 0000000..e14272a
--- /dev/null
+++ b/tests/fixtures/mempool/mempool-empty.json
@@ -0,0 +1,8 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "buckets": [],
+ "total": 0
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/mempool/mempool.json b/tests/fixtures/mempool/mempool.json
new file mode 100644
index 0000000..b999530
--- /dev/null
+++ b/tests/fixtures/mempool/mempool.json
@@ -0,0 +1,9 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "1": 3,
+ "buckets": [1],
+ "total": 3
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/mempoolContent/full-transactions.json b/tests/fixtures/mempoolContent/full-transactions.json
new file mode 100644
index 0000000..3844335
--- /dev/null
+++ b/tests/fixtures/mempoolContent/full-transactions.json
@@ -0,0 +1,39 @@
+{
+ "jsonrpc": "2.0",
+ "result": [
+ {
+ "hash": "5bb722c2afe25c18ba33d453b3ac2c90ac278c595cc92f6188c8b699e8fb006a",
+ "from": "f3a2a520967fb046deee40af0c68c3dc43ef3238",
+ "fromAddress": "NQ04 XEHA A84N FXQ4 DPPE 82PG QS63 TH1X XCHQ",
+ "to": "ca9e687c4e760e5d6dd4a789c577cefe1338ad2c",
+ "toAddress": "NQ77 RAF6 GY2E EQ75 STEL LX4U AVXE YQ9K HB9C",
+ "value": 9286543536,
+ "fee": 1380,
+ "data": null,
+ "flags": 0
+ },
+ {
+ "hash": "f59a30e0a7e3348ef569225db1f4c29026aeac4350f8c6e751f669eddce0c718",
+ "from": "f3a2a520967fb046deee40af0c68c3dc43ef3238",
+ "fromAddress": "NQ04 XEHA A84N FXQ4 DPPE 82PG QS63 TH1X XCHQ",
+ "to": "1a5ac816ace8ee339f7ec80f580ef9ea17b8b32b",
+ "toAddress": "NQ85 39DC G5MC V3P3 77TX R07M G3PR V8BT HCRB",
+ "value": 5314650699,
+ "fee": 1380,
+ "data": null,
+ "flags": 0
+ },
+ {
+ "hash": "9cd9c1d0ffcaebfcfe86bc2ae73b4e82a488de99c8e3faef92b05432bb94519c",
+ "from": "f3a2a520967fb046deee40af0c68c3dc43ef3238",
+ "fromAddress": "NQ04 XEHA A84N FXQ4 DPPE 82PG QS63 TH1X XCHQ",
+ "to": "d497b15fe0857394f3e485c87e00fa44270fcd4d",
+ "toAddress": "NQ60 SJBT 2PY0 GMRR 9UY4 GP47 U07S 8GKG YKAD",
+ "value": 1038143325,
+ "fee": 1380,
+ "data": null,
+ "flags": 0
+ }
+ ],
+ "id": 1
+}
diff --git a/tests/fixtures/mempoolContent/hashes-only.json b/tests/fixtures/mempoolContent/hashes-only.json
new file mode 100644
index 0000000..1c0cb72
--- /dev/null
+++ b/tests/fixtures/mempoolContent/hashes-only.json
@@ -0,0 +1,9 @@
+{
+ "jsonrpc": "2.0",
+ "result": [
+ "5bb722c2afe25c18ba33d453b3ac2c90ac278c595cc92f6188c8b699e8fb006a",
+ "f59a30e0a7e3348ef569225db1f4c29026aeac4350f8c6e751f669eddce0c718",
+ "9cd9c1d0ffcaebfcfe86bc2ae73b4e82a488de99c8e3faef92b05432bb94519c"
+ ],
+ "id": 1
+}
diff --git a/tests/fixtures/minFeePerByte/fee.json b/tests/fixtures/minFeePerByte/fee.json
new file mode 100644
index 0000000..0313be6
--- /dev/null
+++ b/tests/fixtures/minFeePerByte/fee.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": 0,
+ "id": 1
+}
diff --git a/tests/fixtures/minerAddress/address.json b/tests/fixtures/minerAddress/address.json
new file mode 100644
index 0000000..3015fd4
--- /dev/null
+++ b/tests/fixtures/minerAddress/address.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": "NQ39 NY67 X0F0 UTQE 0YER 4JEU B67L UPP8 G0FM",
+ "id": 1
+}
diff --git a/tests/fixtures/minerThreads/threads.json b/tests/fixtures/minerThreads/threads.json
new file mode 100644
index 0000000..49eab50
--- /dev/null
+++ b/tests/fixtures/minerThreads/threads.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": 2,
+ "id": 1
+}
diff --git a/tests/fixtures/miningState/mining.json b/tests/fixtures/miningState/mining.json
new file mode 100644
index 0000000..b3f2d66
--- /dev/null
+++ b/tests/fixtures/miningState/mining.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": false,
+ "id": 1
+}
diff --git a/tests/fixtures/peerCount/count.json b/tests/fixtures/peerCount/count.json
new file mode 100644
index 0000000..85b2a60
--- /dev/null
+++ b/tests/fixtures/peerCount/count.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": 6,
+ "id": 1
+}
diff --git a/tests/fixtures/peerList/empty-list.json b/tests/fixtures/peerList/empty-list.json
new file mode 100644
index 0000000..1ae04ea
--- /dev/null
+++ b/tests/fixtures/peerList/empty-list.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": [],
+ "id": 1
+}
diff --git a/tests/fixtures/peerList/list.json b/tests/fixtures/peerList/list.json
new file mode 100644
index 0000000..4f60a22
--- /dev/null
+++ b/tests/fixtures/peerList/list.json
@@ -0,0 +1,23 @@
+{
+ "jsonrpc": "2.0",
+ "result": [
+ {
+ "id": "b99034c552e9c0fd34eb95c1cdf17f5e",
+ "address": "wss://seed1.nimiq-testnet.com:8080/b99034c552e9c0fd34eb95c1cdf17f5e",
+ "addressState": 2,
+ "connectionState": 5,
+ "version": 2,
+ "timeOffset": -188,
+ "headHash": "59da8ba57c1f0ffd444201ca2d9f48cef7e661262781be7937bb6ef0bdbe0e4d",
+ "latency": 532,
+ "rx": 2122,
+ "tx": 1265
+ },
+ {
+ "id": "e37dca72802c972d45b37735e9595cf0",
+ "address": "wss://seed4.nimiq-testnet.com:8080/e37dca72802c972d45b37735e9595cf0",
+ "addressState": 4
+ }
+ ],
+ "id": 1
+}
diff --git a/tests/fixtures/peerState/error.json b/tests/fixtures/peerState/error.json
new file mode 100644
index 0000000..341b864
--- /dev/null
+++ b/tests/fixtures/peerState/error.json
@@ -0,0 +1,8 @@
+{
+ "jsonrpc": "2.0",
+ "error": {
+ "code": 1,
+ "message": "Invalid or unknown peer address"
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/peerState/failed.json b/tests/fixtures/peerState/failed.json
new file mode 100644
index 0000000..5ddd109
--- /dev/null
+++ b/tests/fixtures/peerState/failed.json
@@ -0,0 +1,9 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "id": "e37dca72802c972d45b37735e9595cf0",
+ "address": "wss://seed4.nimiq-testnet.com:8080/e37dca72802c972d45b37735e9595cf0",
+ "addressState": 4
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/peerState/normal.json b/tests/fixtures/peerState/normal.json
new file mode 100644
index 0000000..fa4b045
--- /dev/null
+++ b/tests/fixtures/peerState/normal.json
@@ -0,0 +1,16 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "id": "b99034c552e9c0fd34eb95c1cdf17f5e",
+ "address": "wss://seed1.nimiq-testnet.com:8080/b99034c552e9c0fd34eb95c1cdf17f5e",
+ "addressState": 2,
+ "connectionState": 5,
+ "version": 2,
+ "timeOffset": 186,
+ "headHash": "910a78e761034e0655bf01b13336793c809f598194a1b841269600ef8b84fe18",
+ "latency": 550,
+ "rx": 3440,
+ "tx": 2696
+ },
+ "id": 1
+}
diff --git a/tests/fixtures/pool/confirmed-balance.json b/tests/fixtures/pool/confirmed-balance.json
new file mode 100644
index 0000000..2f7c9f6
--- /dev/null
+++ b/tests/fixtures/pool/confirmed-balance.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": 12000,
+ "id": 1
+}
diff --git a/tests/fixtures/pool/connection-state.json b/tests/fixtures/pool/connection-state.json
new file mode 100644
index 0000000..49eab50
--- /dev/null
+++ b/tests/fixtures/pool/connection-state.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": 2,
+ "id": 1
+}
diff --git a/tests/fixtures/pool/no-pool.json b/tests/fixtures/pool/no-pool.json
new file mode 100644
index 0000000..2fbb1ed
--- /dev/null
+++ b/tests/fixtures/pool/no-pool.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": null,
+ "id": 1
+}
diff --git a/tests/fixtures/pool/sushipool.json b/tests/fixtures/pool/sushipool.json
new file mode 100644
index 0000000..6e0a671
--- /dev/null
+++ b/tests/fixtures/pool/sushipool.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": "us.sushipool.com:443",
+ "id": 1
+}
diff --git a/tests/fixtures/sendTransaction/transaction.json b/tests/fixtures/sendTransaction/transaction.json
new file mode 100644
index 0000000..361a7f2
--- /dev/null
+++ b/tests/fixtures/sendTransaction/transaction.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": "81cf3f07b6b0646bb16833d57cda801ad5957e264b64705edeef6191fea0ad63",
+ "id": 1
+}
diff --git a/tests/fixtures/submitBlock/submit.json b/tests/fixtures/submitBlock/submit.json
new file mode 100644
index 0000000..aa832d9
--- /dev/null
+++ b/tests/fixtures/submitBlock/submit.json
@@ -0,0 +1,4 @@
+{
+ "jsonrpc": "2.0",
+ "id": 1
+}
diff --git a/tests/fixtures/syncing/not-syncing.json b/tests/fixtures/syncing/not-syncing.json
new file mode 100644
index 0000000..b3f2d66
--- /dev/null
+++ b/tests/fixtures/syncing/not-syncing.json
@@ -0,0 +1,5 @@
+{
+ "jsonrpc": "2.0",
+ "result": false,
+ "id": 1
+}
diff --git a/tests/fixtures/syncing/syncing.json b/tests/fixtures/syncing/syncing.json
new file mode 100644
index 0000000..fa50969
--- /dev/null
+++ b/tests/fixtures/syncing/syncing.json
@@ -0,0 +1,9 @@
+{
+ "jsonrpc": "2.0",
+ "result": {
+ "startingBlock": 578430,
+ "currentBlock": 586493,
+ "highestBlock": 586493
+ },
+ "id": 1
+}