├── .php-cs-fixer.dist.php ├── LICENSE.md ├── composer.json └── src ├── Concerns └── Transportable.php ├── Contracts ├── Formatter.php └── Transporter.php ├── Exceptions ├── ErrorException.php ├── InvalidHexException.php ├── InvalidUrlException.php └── TransporterException.php ├── Formatters ├── BigIntegerToHex.php ├── HexToBigInteger.php ├── HexToWei.php └── StringToHex.php ├── Namespaces ├── Eth.php ├── Net.php └── Web3.php ├── Transporters └── Http.php ├── ValueObjects ├── Transaction.php └── Wei.php └── Web3.php /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in(__DIR__ . DIRECTORY_SEPARATOR . 'tests') 5 | ->in(__DIR__ . DIRECTORY_SEPARATOR . 'src') 6 | ->append(['.php_cs']); 7 | 8 | $rules = [ 9 | '@Symfony' => true, 10 | 'phpdoc_no_empty_return' => false, 11 | 'phpdoc_types_order' => false, 12 | 'phpdoc_to_comment' => false, 13 | 'array_syntax' => ['syntax' => 'short'], 14 | 'yoda_style' => false, 15 | 'binary_operator_spaces' => [ 16 | 'operators' => [ 17 | '=>' => 'align', 18 | '=' => 'align', 19 | ], 20 | ], 21 | 'concat_space' => ['spacing' => 'one'], 22 | 'not_operator_with_space' => false, 23 | ]; 24 | 25 | $rules['increment_style'] = ['style' => 'post']; 26 | 27 | return (new PhpCsFixer\Config()) 28 | ->setUsingCache(true) 29 | ->setRules($rules) 30 | ->setFinder($finder); 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Nuno Maduro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web3-php/web3", 3 | "description": "Web3 PHP is a supercharged PHP API client that allows you to interact with a generic Ethereum RPC.", 4 | "keywords": ["php", "web3", "ethereum", "json-rpc", "api", "client"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Nuno Maduro", 9 | "email": "enunomaduro@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "php": "^8.0", 14 | "ext-bcmath": "*", 15 | "guzzlehttp/guzzle": "^7.4.1", 16 | "phpseclib/phpseclib": "^3.0.13" 17 | }, 18 | "require-dev": { 19 | "friendsofphp/php-cs-fixer": "^3.6.0", 20 | "mockery/mockery": "^1.5.0", 21 | "pestphp/pest": "^2.0.0", 22 | "phpstan/phpstan": "^1.4.6", 23 | "symfony/var-dumper": "^5.4.3" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Web3\\": "src/" 28 | } 29 | }, 30 | "autoload-dev": { 31 | "psr-4": { 32 | "Tests\\": "tests/" 33 | } 34 | }, 35 | "minimum-stability": "dev", 36 | "prefer-stable": true, 37 | "config": { 38 | "sort-packages": true, 39 | "preferred-install": "dist", 40 | "allow-plugins": { 41 | "pestphp/pest-plugin": true 42 | } 43 | }, 44 | "scripts": { 45 | "lint": "PHP_CS_FIXER_IGNORE_ENV=true php-cs-fixer fix -v", 46 | "test:lint": "PHP_CS_FIXER_IGNORE_ENV=true php-cs-fixer fix -v --dry-run", 47 | "test:types": "phpstan analyse --ansi", 48 | "test:unit": "pest --colors=always", 49 | "test": [ 50 | "@test:lint", 51 | "@test:types", 52 | "@test:unit" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Concerns/Transportable.php: -------------------------------------------------------------------------------- 1 | transporter)) { 30 | return $this->transporter; 31 | } 32 | 33 | if (str_starts_with($this->url, '127')) { 34 | $this->transporter = new Http(new Client(), sprintf('http://%s', $this->url)); 35 | } 36 | 37 | if (str_starts_with($this->url, 'http')) { 38 | $this->transporter = new Http(new Client(), $this->url); 39 | } 40 | 41 | if (is_null($this->transporter)) { 42 | throw new InvalidUrlException('The given url must start by "http".'); 43 | } 44 | 45 | return $this->transporter; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Contracts/Formatter.php: -------------------------------------------------------------------------------- 1 | $params 19 | * 20 | * @throws ErrorException|TransporterException 21 | * 22 | * @return array|string|bool 23 | */ 24 | public function request(string $method, array $params = []): array|string|bool; 25 | } 26 | -------------------------------------------------------------------------------- /src/Exceptions/ErrorException.php: -------------------------------------------------------------------------------- 1 | message(), $this->code()); 21 | } 22 | 23 | /** 24 | * Gets the error code. 25 | */ 26 | public function code(): int 27 | { 28 | return (int) $this->error['code']; 29 | } 30 | 31 | /** 32 | * Gets the error message. 33 | */ 34 | public function message(): string 35 | { 36 | return $this->error['message']; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Exceptions/InvalidHexException.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | final class BigIntegerToHex implements Formatter 16 | { 17 | /** 18 | * {@inheritDoc} 19 | */ 20 | public static function format(string $value): string 21 | { 22 | if (str_starts_with($value, '0x')) { 23 | return $value; 24 | } 25 | 26 | $bigInteger = new BigInteger($value); 27 | 28 | return '0x' . $bigInteger->toHex(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Formatters/HexToBigInteger.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | final class HexToBigInteger implements Formatter 16 | { 17 | /** 18 | * {@inheritDoc} 19 | */ 20 | public static function format(string $value): string 21 | { 22 | $bigInteger = new BigInteger($value, 16); 23 | 24 | return $bigInteger->toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Formatters/HexToWei.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | final class HexToWei implements Formatter 16 | { 17 | /** 18 | * {@inheritDoc} 19 | */ 20 | public static function format(string $value): Wei 21 | { 22 | return Wei::fromHex($value); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Formatters/StringToHex.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | final class StringToHex implements Formatter 15 | { 16 | /** 17 | * {@inheritDoc} 18 | */ 19 | public static function format(string $value): string 20 | { 21 | if (str_starts_with($value, '0x') && ctype_xdigit(substr($value, 2))) { 22 | return $value; 23 | } 24 | 25 | return '0x' . bin2hex($value); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Namespaces/Eth.php: -------------------------------------------------------------------------------- 1 | 30 | * 31 | * @throws ErrorException|TransporterException 32 | */ 33 | public function accounts(): array 34 | { 35 | $result = $this->transporter->request('eth_accounts'); 36 | 37 | /** @var array $result */ 38 | assert(is_array($result)); 39 | 40 | return $result; 41 | } 42 | 43 | /** 44 | * Returns the current chain id. 45 | * 46 | * @throws ErrorException|TransporterException 47 | */ 48 | public function chainId(): string 49 | { 50 | $result = $this->transporter->request('eth_chainId'); 51 | 52 | assert(is_string($result)); 53 | 54 | return HexToBigInteger::format($result); 55 | } 56 | 57 | /** 58 | * Returns the current price of gas in wei. 59 | * 60 | * @throws ErrorException|TransporterException 61 | */ 62 | public function gasPrice(): Wei 63 | { 64 | $result = $this->transporter->request('eth_gasPrice'); 65 | 66 | assert(is_string($result)); 67 | 68 | return HexToWei::format($result); 69 | } 70 | 71 | /** 72 | * Returns the balance of an address in wei. 73 | * 74 | * @throws ErrorException|TransporterException 75 | */ 76 | public function getBalance(string $address, string $defaultBlock = null): Wei 77 | { 78 | $result = $this->transporter->request('eth_getBalance', [ 79 | $address, 80 | $defaultBlock ?: 'latest', 81 | ]); 82 | 83 | assert(is_string($result)); 84 | 85 | return HexToWei::format($result); 86 | } 87 | 88 | /** 89 | * Returns the number of transactions in a block by its hash. 90 | * 91 | * @throws ErrorException|TransporterException 92 | */ 93 | public function getBlockTransactionCountByHash(string $blockHash): string 94 | { 95 | $result = $this->transporter->request('eth_getBlockTransactionCountByHash', [ 96 | $blockHash, 97 | ]); 98 | 99 | assert(is_string($result)); 100 | 101 | return HexToBigInteger::format($result); 102 | } 103 | 104 | /** 105 | * Returns the number of transactions in a block by its number or identifier. 106 | * 107 | * @throws ErrorException|TransporterException 108 | */ 109 | public function getBlockTransactionCountByNumber(string|int $blockIdentifier): string 110 | { 111 | if (is_int($blockIdentifier)) { 112 | $blockIdentifier = BigIntegerToHex::format((string) $blockIdentifier); 113 | } 114 | 115 | $result = $this->transporter->request('eth_getBlockTransactionCountByNumber', [ 116 | $blockIdentifier, 117 | ]); 118 | 119 | assert(is_string($result)); 120 | 121 | return HexToBigInteger::format($result); 122 | } 123 | 124 | /** 125 | * Returns information about a transaction by its hash. 126 | * 127 | * @return array 128 | * 129 | * @throws ErrorException|TransporterException 130 | */ 131 | public function getTransactionByHash(string $transactionHash): array 132 | { 133 | $result = $this->transporter->request('eth_getTransactionByHash', [ 134 | $transactionHash, 135 | ]); 136 | 137 | /** @var array $result */ 138 | assert(is_array($result)); 139 | 140 | foreach (['blockNumber', 'gas', 'gasPrice', 'nonce', 'transactionIndex', 'value', 'v'] as $key) { 141 | $result[$key] = HexToBigInteger::format($result[$key]); 142 | } 143 | 144 | return $result; 145 | } 146 | 147 | /** 148 | * Returns the receipt of a transaction by its hash. 149 | * Note that the receipt is not available for pending transactions. 150 | * 151 | * @return array> 152 | * 153 | * @throws ErrorException|TransporterException 154 | */ 155 | public function getTransactionReceipt(string $transactionHash): array 156 | { 157 | $result = $this->transporter->request('eth_getTransactionReceipt', [ 158 | $transactionHash, 159 | ]); 160 | 161 | /** @var array> $result */ 162 | assert(is_array($result)); 163 | 164 | foreach (['blockNumber', 'cumulativeGasUsed', 'gasUsed', 'status', 'transactionIndex'] as $key) { 165 | assert(is_string($result[$key])); 166 | 167 | $result[$key] = HexToBigInteger::format($result[$key]); 168 | } 169 | 170 | assert(is_array($result['logs'])); 171 | 172 | /** @var array $log */ 173 | foreach ($result['logs'] ?? [] as $logKey => $log) { 174 | foreach (['blockNumber', 'logIndex', 'transactionIndex'] as $key) { 175 | $result['logs'][$logKey][$key] = HexToBigInteger::format($log[$key]); 176 | } 177 | } 178 | 179 | return $result; 180 | } 181 | 182 | /** 183 | * Returns the number of uncles in a block by its hash. 184 | * 185 | * @throws ErrorException|TransporterException 186 | */ 187 | public function getUncleCountByBlockHash(string $blockHash): string 188 | { 189 | $result = $this->transporter->request('eth_getUncleCountByBlockHash', [ 190 | $blockHash, 191 | ]); 192 | 193 | assert(is_string($result)); 194 | 195 | return HexToBigInteger::format($result); 196 | } 197 | 198 | /** 199 | * Returns the number of hashes-per-second this node is mining at. 200 | * 201 | * @throws ErrorException|TransporterException 202 | */ 203 | public function hashrate(): string 204 | { 205 | $result = $this->transporter->request('eth_hashrate'); 206 | 207 | assert(is_string($result)); 208 | 209 | return HexToBigInteger::format($result); 210 | } 211 | 212 | /** 213 | * Determines if the client is mining new blocks. 214 | * 215 | * @throws ErrorException|TransporterException 216 | */ 217 | public function isMining(): bool 218 | { 219 | $result = $this->transporter->request('eth_mining'); 220 | 221 | assert(is_bool($result)); 222 | 223 | return $result; 224 | } 225 | 226 | /** 227 | * Returns the number (quantity) of the most recent block seen by the client. 228 | * 229 | * @throws ErrorException|TransporterException 230 | */ 231 | public function blockNumber(): string 232 | { 233 | $result = $this->transporter->request('eth_blockNumber'); 234 | 235 | assert(is_string($result)); 236 | 237 | return HexToBigInteger::format($result); 238 | } 239 | 240 | /** 241 | * Returns the coinbase address of the client. 242 | * 243 | * @throws ErrorException|TransporterException 244 | */ 245 | public function coinbase(): string 246 | { 247 | $result = $this->transporter->request('eth_coinbase'); 248 | 249 | assert(is_string($result)); 250 | 251 | return $result; 252 | } 253 | 254 | /** 255 | * Creates, signs, and sends a new transaction to the network. 256 | * 257 | * @throws ErrorException|TransporterException 258 | */ 259 | public function sendTransaction(Transaction $transaction): string 260 | { 261 | $result = $this->transporter->request('eth_sendTransaction', $transaction->toArray()); 262 | 263 | assert(is_string($result)); 264 | 265 | return $result; 266 | } 267 | 268 | /** 269 | * Submit a proof-of-work solution. 270 | * 271 | * @throws ErrorException|TransporterException 272 | */ 273 | public function submitWork(string $nonce, string $proofOfWorkHash, string $mixDigest): bool 274 | { 275 | $result = $this->transporter->request('eth_submitWork', [ 276 | $nonce, 277 | $proofOfWorkHash, 278 | $mixDigest, 279 | ]); 280 | 281 | assert(is_bool($result)); 282 | 283 | return $result; 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /src/Namespaces/Net.php: -------------------------------------------------------------------------------- 1 | transporter->request('net_listening'); 30 | 31 | assert(is_bool($result)); 32 | 33 | return $result; 34 | } 35 | 36 | /** 37 | * Returns the number of peers currently connected to this client. 38 | * 39 | * @throws ErrorException|TransporterException 40 | */ 41 | public function peerCount(): string 42 | { 43 | $result = $this->transporter->request('net_peerCount'); 44 | 45 | assert(is_string($result)); 46 | 47 | return HexToBigInteger::format($result); 48 | } 49 | 50 | /** 51 | * Returns the chain ID associated with the current network. 52 | * 53 | * @throws ErrorException|TransporterException 54 | */ 55 | public function version(): string 56 | { 57 | $result = $this->transporter->request('net_version'); 58 | 59 | assert(is_string($result)); 60 | 61 | return $result; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Namespaces/Web3.php: -------------------------------------------------------------------------------- 1 | transporter->request('web3_clientVersion'); 30 | 31 | assert(is_string($result)); 32 | 33 | return $result; 34 | } 35 | 36 | /** 37 | * Hashes data using the Keccak-256 algorithm. 38 | * 39 | * @throws ErrorException|TransporterException 40 | */ 41 | public function sha3(string $data): string 42 | { 43 | $data = StringToHex::format($data); 44 | 45 | $result = $this->transporter->request('web3_sha3', [$data]); 46 | 47 | assert(is_string($result)); 48 | 49 | return $result; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Transporters/Http.php: -------------------------------------------------------------------------------- 1 | '2.0', 33 | 'id' => '1', 34 | 'method' => $method, 35 | 'params' => $params, 36 | ]); 37 | 38 | $headers = [ 39 | 'Content-Type' => 'application/json', 40 | 'Content-Length' => (string) strlen($body), 41 | ]; 42 | 43 | $request = new Request('POST', $this->url, $headers, $body); 44 | 45 | try { 46 | $contents = $this->client->sendRequest($request)->getBody()->getContents(); 47 | } catch (ClientExceptionInterface $clientException) { 48 | /** @var int $code */ 49 | $code = $clientException->getCode(); 50 | $message = $clientException->getMessage(); 51 | 52 | throw new TransporterException($message, $code, $clientException); 53 | } 54 | 55 | /** @var array{'error'?: array{'code': int, 'message': string}, 'result': array|string|bool}} $response */ 56 | $response = json_decode($contents, true); 57 | 58 | if (array_key_exists('error', $response)) { 59 | throw new ErrorException($response['error']); 60 | } 61 | 62 | return $response['result']; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/ValueObjects/Transaction.php: -------------------------------------------------------------------------------- 1 | $options 15 | */ 16 | private function __construct( 17 | private string $from, private string $to, private array $options, 18 | ) { 19 | // .. 20 | } 21 | 22 | /** 23 | * Creates a new Transaction instance between the given accounts. 24 | * 25 | * @param array $options 26 | */ 27 | public static function between(string $from, string $to, array $options = []): self 28 | { 29 | foreach (['value', 'gas', 'gasPrice', 'nonce'] as $option) { 30 | if (array_key_exists($option, $options)) { 31 | $options[$option] = BigIntegerToHex::format($options[$option]); 32 | } 33 | } 34 | 35 | return new self($from, $to, $options); 36 | } 37 | 38 | /** 39 | * Creates a new Transaction instance with the given value in wei. 40 | */ 41 | public function withValue(Wei $wei): self 42 | { 43 | return self::between($this->from, $this->to, array_merge($this->options, [ 44 | 'value' => $wei->value(), 45 | ])); 46 | } 47 | 48 | /** 49 | * Creates a new Transaction instance with the given gas in wei. 50 | * 51 | * Gas is the gas provided for transaction execution. 52 | */ 53 | public function withGas(string $quantity): self 54 | { 55 | return self::between($this->from, $this->to, array_merge($this->options, [ 56 | 'gas' => $quantity, 57 | ])); 58 | } 59 | 60 | /** 61 | * Creates a new Transaction instance with the given gas price in wei. 62 | * 63 | * Gas Price is the price in wei of each gas used. 64 | */ 65 | public function withGasPrice(Wei $wei): self 66 | { 67 | return self::between($this->from, $this->to, array_merge($this->options, [ 68 | 'gasPrice' => $wei->value(), 69 | ])); 70 | } 71 | 72 | /** 73 | * Creates a new Transaction instance with the given nonce. 74 | * 75 | * Nonce is the unique number identifying this transaction. 76 | */ 77 | public function withNonce(string $number): self 78 | { 79 | return self::between($this->from, $this->to, array_merge($this->options, [ 80 | 'nonce' => $number, 81 | ])); 82 | } 83 | 84 | /** 85 | * Returns the array representation of the Transaction. 86 | * 87 | * @return array 88 | * 89 | * @internal 90 | */ 91 | public function toArray(): array 92 | { 93 | return array_filter([ 94 | 'from' => $this->from, 95 | 'to' => $this->to, 96 | 'value' => $this->options['value'] ?? null, 97 | 'gas' => $this->options['gas'] ?? null, 98 | 'gasPrice' => $this->options['gasPrice'] ?? null, 99 | 'nonce' => $this->options['nonce'] ?? null, 100 | ]); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/ValueObjects/Wei.php: -------------------------------------------------------------------------------- 1 | value; 47 | } 48 | 49 | /** 50 | * Gets Wei's value. 51 | */ 52 | public function toWei(): string 53 | { 54 | return $this->value(); 55 | } 56 | 57 | /** 58 | * Gets Wei's Kwei value. 59 | */ 60 | public function toKwei(): string 61 | { 62 | return self::div($this->value, 1000); 63 | } 64 | 65 | /** 66 | * Gets Wei's Mwei value. 67 | */ 68 | public function toMwei(): string 69 | { 70 | return self::div($this->value, 1000000); 71 | } 72 | 73 | /** 74 | * Gets Wei's Gwei value. 75 | */ 76 | public function toGwei(): string 77 | { 78 | return self::div($this->value, 1000000000); 79 | } 80 | 81 | /** 82 | * Gets the tWei's ther value. 83 | */ 84 | public function toMicroether(): string 85 | { 86 | return self::div($this->value, 1000000000000); 87 | } 88 | 89 | /** 90 | * Gets the tWei's ther value. 91 | */ 92 | public function toMilliether(): string 93 | { 94 | return self::div($this->value, 1000000000000000); 95 | } 96 | 97 | /** 98 | * Gets tWei's ether value. 99 | */ 100 | public function toEther(): string 101 | { 102 | return self::div($this->value, 1000000000000000000); 103 | } 104 | 105 | /** 106 | * Gets Wei's Eth value. 107 | */ 108 | public function toEth(): string 109 | { 110 | return $this->toEther(); 111 | } 112 | 113 | /** 114 | * Gets the Wei's string representation. 115 | */ 116 | public function toString(): string 117 | { 118 | return $this->value(); 119 | } 120 | 121 | /** 122 | * Gets the Wei's string representation. 123 | */ 124 | public function __toString(): string 125 | { 126 | return $this->toString(); 127 | } 128 | 129 | /** 130 | * Formats the current value by the given divider. 131 | */ 132 | private static function div(string $value, int $divider): string 133 | { 134 | $scale = strlen((string) $divider); 135 | 136 | $value = bcdiv($value, (string) $divider, $scale); 137 | 138 | assert(is_string($value)); 139 | 140 | return self::format($value); 141 | } 142 | 143 | /** 144 | * Formats the current value by the given multiplier. 145 | */ 146 | private static function mul(string $value, int $multiplier): string 147 | { 148 | $bigInteger = (new BigInteger($value))->multiply(new BigInteger($multiplier)); 149 | 150 | return self::format($bigInteger->toString()); 151 | } 152 | 153 | /** 154 | * Formats the given string, removing trailing zeros. 155 | */ 156 | private static function format(string $value): string 157 | { 158 | if (str_contains($value, '.')) { 159 | $value = rtrim($value, '0'); 160 | } 161 | 162 | return rtrim($value, '.'); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/Web3.php: -------------------------------------------------------------------------------- 1 | getTransporter()); 33 | } 34 | 35 | /** 36 | * Creates a new Net instance. 37 | */ 38 | public function net(): Net 39 | { 40 | return new Net($this->getTransporter()); 41 | } 42 | 43 | /** 44 | * Dynamically handle calls to the namespace. 45 | * 46 | * @param array> $params 47 | * 48 | * @throws ErrorException|TransporterException 49 | * 50 | * @return array|string|bool 51 | */ 52 | public function __call(string $method, array $params = []): array|string|bool 53 | { 54 | return (new Namespaces\Web3($this->getTransporter()))->{$method}(...$params); 55 | } 56 | } 57 | --------------------------------------------------------------------------------