jsonRPCClient.php 5.61 KB
Newer Older
beardedwarrior's avatar
beardedwarrior committed
1 2 3 4
<?php

namespace Monero;

5 6 7
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;
beardedwarrior's avatar
beardedwarrior committed
8 9 10 11 12

/**
 * Class jsonRPCClient
 * JSON 2.0 RPC Client for cryptocurrency wallet
 */
13
class jsonRPCClient implements Contracts\WalletManager
beardedwarrior's avatar
beardedwarrior committed
14 15
{

16
    /** @var string */
17
    private $username = 'test2';
beardedwarrior's avatar
beardedwarrior committed
18

19
    /** @var string */
20 21 22 23
    private $password = 'test2';

    /** @var string  */
    private $url = 'http://127.0.0.1:28080/json_rpc';
24 25 26

    /** @var Client|null  */
    private $client;
beardedwarrior's avatar
beardedwarrior committed
27 28

    /**
29
     * JsonRPCClient constructor.
30
     * @param array $options
31
     * @param null $client
beardedwarrior's avatar
beardedwarrior committed
32
     */
33
    public function __construct($options, $client = null)
34
    {
35 36 37 38
        $this->username = $options['username'] ?? $this->username;
        $this->password = $options['password'] ?? $this->password;
        $this->url = $options['url'] ?? $this->url;

39 40
        if (empty($client)) {
            $client = new Client([
41 42 43 44
                'base_uri' => $this->url,
                'headers' => [
                    'Content-Type' => 'application/json',
                ]
45 46
            ]);
        }
47

48 49
        $this->client = $client;
    }
beardedwarrior's avatar
beardedwarrior committed
50 51

    /**
52 53 54
     * Gets the balance
     *
     * @return int the overall value after inputs unlock
beardedwarrior's avatar
beardedwarrior committed
55
     */
56 57 58 59 60
    public function balance() : int
    {
        $response = $this->request('get_balance');
        return $response['balance'];
    }
beardedwarrior's avatar
beardedwarrior committed
61 62

    /**
63 64 65
     * Gets the unlocked balance
     *
     * @return int the spendable balance
beardedwarrior's avatar
beardedwarrior committed
66
     */
67 68 69 70 71
    public function unlockedBalance() : int
    {
        $response = $this->request('get_balance');
        return $response['unlocked_balance'];
    }
beardedwarrior's avatar
beardedwarrior committed
72 73

    /**
74
     * Gets the primary address
beardedwarrior's avatar
beardedwarrior committed
75
     *
76
     * @return string wallets primary address
beardedwarrior's avatar
beardedwarrior committed
77
     */
78
    public function address() : string
beardedwarrior's avatar
beardedwarrior committed
79
    {
80 81
        $response = $this->request('get_address');
        return $response['address'];
beardedwarrior's avatar
beardedwarrior committed
82 83 84
    }

    /**
85
     * Gets the current block height
beardedwarrior's avatar
beardedwarrior committed
86
     *
87
     * @return int block height
beardedwarrior's avatar
beardedwarrior committed
88
     */
89
    public function blockHeight() : int
beardedwarrior's avatar
beardedwarrior committed
90
    {
91 92
        $response = $this->request('get_height');
        return $response['height'];
beardedwarrior's avatar
beardedwarrior committed
93 94
    }
    /**
95
     * Creates a new integrated address
beardedwarrior's avatar
beardedwarrior committed
96
     *
97
     * @return array ['integrated_address', 'payment_id']
beardedwarrior's avatar
beardedwarrior committed
98
     */
99
    public function createIntegratedAddress() : array
beardedwarrior's avatar
beardedwarrior committed
100
    {
101 102
        $response = $this->request('make_integrated_address');
        return $response;
beardedwarrior's avatar
beardedwarrior committed
103 104 105
    }

    /**
106
     * Gets any incoming transactions
beardedwarrior's avatar
beardedwarrior committed
107
     *
108
     * @return array
beardedwarrior's avatar
beardedwarrior committed
109
     */
110
    public function incomingTransfers() : array
beardedwarrior's avatar
beardedwarrior committed
111
    {
112 113 114
        $response = $this->request('get_transfers', ['pool' => true, 'in' => true]);

        return $response;
beardedwarrior's avatar
beardedwarrior committed
115 116 117
    }

    /**
118
     * Checks for any payments made to the paymentIds
beardedwarrior's avatar
beardedwarrior committed
119
     *
120 121
     * @param array     $paymentIds list of payment ids to be searched for
     * @param int       $minHeight  the lowest block the search should start with
beardedwarrior's avatar
beardedwarrior committed
122
     *
123
     * @return array    payments received since min block height with a payment id provided
beardedwarrior's avatar
beardedwarrior committed
124
     */
125
    public function payments($paymentIds, $minHeight) : array
beardedwarrior's avatar
beardedwarrior committed
126
    {
127
        $response = $this->request('get_bulk_payments', ['payment_ids' => $paymentIds, 'min_block_height' => $minHeight]);
beardedwarrior's avatar
beardedwarrior committed
128

129
        return $response;
beardedwarrior's avatar
beardedwarrior committed
130 131
    }

132 133 134 135 136 137 138 139 140 141
    /**
     * creates a uri for easier wallet parsing
     *
     * @param string    $address    address comprising of primary, sub or integrated address
     * @param string    $paymentId  payment id when not using integrated addresses
     * @param int       $amount     atomic amount requested
     *
     * @return string the uri string which can be used to generate a QR code
     */
    public function createUri($address, $paymentId = null, $amount = null) : string
beardedwarrior's avatar
beardedwarrior committed
142
    {
143
        $response = $this->request('make_uri', ['address' => $address, 'amount' => $amount, 'payment_id' => $paymentId]);
beardedwarrior's avatar
beardedwarrior committed
144

145
        return $response['uri'];
beardedwarrior's avatar
beardedwarrior committed
146 147
    }

148 149 150 151 152 153 154 155 156 157
    /**
     * creates a random 64 char payment id
     *
     * @return string
     */
    public function generatePaymentId(): string
    {
        return bin2hex(openssl_random_pseudo_bytes(32));
    }

beardedwarrior's avatar
beardedwarrior committed
158
    /**
159
     * Sets up the request data body
beardedwarrior's avatar
beardedwarrior committed
160
     *
161 162
     * @param string    $method name of the rpc command
     * @param array     $params associative array of variables being passed to the method
beardedwarrior's avatar
beardedwarrior committed
163
     *
164
     * @return false|string will return a json string or false
beardedwarrior's avatar
beardedwarrior committed
165
     */
166
    private function preparePayload($method, $params)
beardedwarrior's avatar
beardedwarrior committed
167 168 169
    {
        $payload = [
            'jsonrpc' => '2.0',
170 171 172
            'id' => '0',
            'method' => $method,
            'params' => $params,
beardedwarrior's avatar
beardedwarrior committed
173
        ];
174
        return json_encode($payload);
beardedwarrior's avatar
beardedwarrior committed
175 176 177
    }

    /**
178
     * Send off request to rpc server
beardedwarrior's avatar
beardedwarrior committed
179
     *
180 181 182 183
     * @param string    $method name of the rpc command
     * @param array     $params associative array of variables being passed to the method
     *
     * @return mixed the rpc query result
beardedwarrior's avatar
beardedwarrior committed
184
     *
185
     * @throws \RuntimeException
beardedwarrior's avatar
beardedwarrior committed
186
     */
187
    protected function request(string $method, array $params = [])
beardedwarrior's avatar
beardedwarrior committed
188
    {
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
        $payload = $this->preparePayload($method, $params);

        try {
            $response = $this->client->request('POST', '',[
                'auth' => [$this->username, $this->password, 'digest'],
                'body' => $payload,
                'headers' => [
                    'Content-Type' => 'application/json',
                ]
            ]);

            $body = $response->getBody();
        } catch (GuzzleException $exception) {
            Log::error($exception);
            throw new \RuntimeException('Connection to node unsuccessful');
beardedwarrior's avatar
beardedwarrior committed
204
        }
205 206
        $result = json_decode((string) $body, true);
        if (isset($result['error'])) {
beardedwarrior's avatar
beardedwarrior committed
207

208
            throw new \RuntimeException($result['error']['message']);
beardedwarrior's avatar
beardedwarrior committed
209
        }
210
        return $result['result'];
beardedwarrior's avatar
beardedwarrior committed
211 212 213
    }

}