From 03a5381a96f07b67f9ce2cad0c5e1c8ede0ef821 Mon Sep 17 00:00:00 2001 From: Lessmore92 Date: Mon, 18 Jan 2021 22:08:27 +0330 Subject: [PATCH] base actions --- .gitignore | 1 + composer.json | 32 + composer.lock | 792 ++++++++++++++++++ .../Contracts/HttpClientInterface.php | 9 + .../Contracts/HttpRequestInterface.php | 8 + .../Contracts/HttpResponseInterface.php | 11 + .../Contracts/ResponseModelInterface.php | 14 + src/Foundation/ResponseModel.php | 13 + src/GuzzleClient/Http.php | 51 ++ src/GuzzleClient/Request.php | 63 ++ src/GuzzleClient/Response.php | 37 + src/Model/Base/Balance.php | 38 + src/Model/Response/AccountInfo.php | 54 ++ src/RippleAPI.php | 139 +++ src/Transaction/Sign.php | 98 +++ src/Utils.php | 74 ++ 16 files changed, 1434 insertions(+) create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 src/Foundation/Contracts/HttpClientInterface.php create mode 100644 src/Foundation/Contracts/HttpRequestInterface.php create mode 100644 src/Foundation/Contracts/HttpResponseInterface.php create mode 100644 src/Foundation/Contracts/ResponseModelInterface.php create mode 100644 src/Foundation/ResponseModel.php create mode 100644 src/GuzzleClient/Http.php create mode 100644 src/GuzzleClient/Request.php create mode 100644 src/GuzzleClient/Response.php create mode 100644 src/Model/Base/Balance.php create mode 100644 src/Model/Response/AccountInfo.php create mode 100644 src/RippleAPI.php create mode 100644 src/Transaction/Sign.php create mode 100644 src/Utils.php diff --git a/.gitignore b/.gitignore index a67d42b..65e4610 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ composer.phar /vendor/ +.idea # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..9f78aae --- /dev/null +++ b/composer.json @@ -0,0 +1,32 @@ +{ + "name": "lessmore92/php-ripple-lib", + "description": "PHP API for interacting with the XRP Ledger", + "keywords": [ + "ripple", + "xrp-ledger", + "xrp", + "ripple-blockchain", + "ripple-api", + "xrpl" + ], + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Lessmore92", + "email": "bahramisoft@gmail.com" + } + ], + "minimum-stability": "dev", + "require": { + "php": ">7", + "lessmore92/php-ripple-keypairs": "v1.0.0", + "lessmore92/php-ripple-binary-codec": "v1.0.0", + "guzzlehttp/guzzle": "7.0" + }, + "autoload": { + "psr-4": { + "Lessmore92\\Ripple\\": "src/" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..ecdb430 --- /dev/null +++ b/composer.lock @@ -0,0 +1,792 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "5dff89a04f20c8ad6a318535f075c53c", + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "414c24961042f6616fb43e23fa69a785f9fc053e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/414c24961042f6616fb43e23fa69a785f9fc053e", + "reference": "414c24961042f6616fb43e23fa69a785f9fc053e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.6.1", + "php": "^7.2.5", + "psr/http-client": "^1.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.0", + "ext-curl": "*", + "php-http/client-integration-tests": "dev-phpunit8", + "phpunit/phpunit": "^8.5.5", + "psr/log": "^1.1" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/master" + }, + "time": "2020-06-27T08:47:54+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "ddfeedfff2a52661429437da0702979f708e6ac6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/ddfeedfff2a52661429437da0702979f708e6ac6", + "reference": "ddfeedfff2a52661429437da0702979f708e6ac6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/master" + }, + "time": "2020-10-19T16:50:15+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f47ece9e6e8ce74e3be04bef47f46061dc18c095" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f47ece9e6e8ce74e3be04bef47f46061dc18c095", + "reference": "f47ece9e6e8ce74e3be04bef47f46061dc18c095", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.x" + }, + "time": "2020-12-08T11:45:39+00:00" + }, + { + "name": "lessmore92/base-x", + "version": "v1.0.3", + "source": { + "type": "git", + "url": "https://github.com/lessmore92/base-x.git", + "reference": "2867d29ef4d3850e2d532d2e543f8303cfdcf80e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lessmore92/base-x/zipball/2867d29ef4d3850e2d532d2e543f8303cfdcf80e", + "reference": "2867d29ef4d3850e2d532d2e543f8303cfdcf80e", + "shasum": "" + }, + "require": { + "lessmore92/buffer": "v1.0.0", + "php": ">=7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lessmore92\\BaseX\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lessmore92", + "email": "bahramisoft@gmail.com" + } + ], + "description": "Encode/decode any base", + "keywords": [ + "base", + "base-x", + "base58", + "base62", + "bitcoin", + "crypto", + "crytography", + "decode", + "decoding", + "encode", + "encoding", + "ethereum", + "ripple" + ], + "support": { + "issues": "https://github.com/lessmore92/base-x/issues", + "source": "https://github.com/lessmore92/base-x/tree/v1.0.3" + }, + "time": "2021-01-11T12:11:54+00:00" + }, + { + "name": "lessmore92/buffer", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/lessmore92/Buffer.git", + "reference": "735337066decb5fa8769359b40bfb0ccd9086d67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lessmore92/Buffer/zipball/735337066decb5fa8769359b40bfb0ccd9086d67", + "reference": "735337066decb5fa8769359b40bfb0ccd9086d67", + "shasum": "" + }, + "require": { + "php-64bit": ">=7.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lessmore92\\Buffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lessmore92", + "email": "bahramisoft@gmail.com" + } + ], + "description": "Toolbox for working with binary and hex data", + "keywords": [ + "Buffer", + "binary", + "hex", + "nodejs-buffer", + "php-buffer" + ], + "support": { + "issues": "https://github.com/lessmore92/Buffer/issues", + "source": "https://github.com/lessmore92/Buffer/tree/v1.0.0" + }, + "time": "2021-01-11T11:55:50+00:00" + }, + { + "name": "lessmore92/php-ripple-address-codec", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/lessmore92/php-ripple-address-codec.git", + "reference": "113e272974a574921145aa962d1d14a5fe0e1761" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lessmore92/php-ripple-address-codec/zipball/113e272974a574921145aa962d1d14a5fe0e1761", + "reference": "113e272974a574921145aa962d1d14a5fe0e1761", + "shasum": "" + }, + "require": { + "lessmore92/base-x": "v1.0.3", + "lessmore92/buffer": "v1.0.0", + "php": ">7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lessmore92\\RippleAddressCodec\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lessmore92", + "email": "bahramisoft@gmail.com" + } + ], + "description": "Library for encoding and decoding XRP Ledger addresses and seeds.", + "keywords": [ + "decoding", + "encoding", + "ripple-address", + "ripple-x-address", + "x-address", + "xaddress", + "xrp", + "xrp-ledger" + ], + "support": { + "issues": "https://github.com/lessmore92/php-ripple-address-codec/issues", + "source": "https://github.com/lessmore92/php-ripple-address-codec/tree/v1.0.0" + }, + "time": "2021-01-11T12:32:09+00:00" + }, + { + "name": "lessmore92/php-ripple-binary-codec", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/lessmore92/php-ripple-binary-codec.git", + "reference": "ba059ce05c60a612daabfd5aa1f61091708ce045" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lessmore92/php-ripple-binary-codec/zipball/ba059ce05c60a612daabfd5aa1f61091708ce045", + "reference": "ba059ce05c60a612daabfd5aa1f61091708ce045", + "shasum": "" + }, + "require": { + "lessmore92/buffer": "v1.0.0", + "lessmore92/php-ripple-address-codec": "v1.0.0", + "php": ">7", + "simplito/bn-php": "~1.1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lessmore92\\RippleBinaryCodec\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lessmore92", + "email": "bahramisoft@gmail.com" + } + ], + "description": "PHP API for interacting with the XRP Ledger", + "keywords": [ + "ripple", + "ripple-tx-signing", + "transaction-signing", + "xrp", + "xrp-ledger" + ], + "support": { + "issues": "https://github.com/lessmore92/php-ripple-binary-codec/issues", + "source": "https://github.com/lessmore92/php-ripple-binary-codec/tree/v1.0.0" + }, + "time": "2021-01-13T00:33:25+00:00" + }, + { + "name": "lessmore92/php-ripple-keypairs", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/lessmore92/php-ripple-keypairs.git", + "reference": "4b763f72d1f923d191a0cee604f48f4eec966714" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lessmore92/php-ripple-keypairs/zipball/4b763f72d1f923d191a0cee604f48f4eec966714", + "reference": "4b763f72d1f923d191a0cee604f48f4eec966714", + "shasum": "" + }, + "require": { + "lessmore92/buffer": "v1.0.0", + "lessmore92/php-ripple-address-codec": "v1.0.0", + "php": ">7", + "simplito/bn-php": "~1.1.0", + "simplito/elliptic-php": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lessmore92\\RippleKeypairs\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lessmore92", + "email": "bahramisoft@gmail.com" + } + ], + "description": "Generate and use keypairs and addresses for the XRP Ledger using elliptic (PHP)", + "keywords": [ + "ripple", + "ripple-keypair", + "ripple-privatekey", + "ripple-seed", + "xrp", + "xrp-ledger", + "xrpl" + ], + "support": { + "issues": "https://github.com/lessmore92/php-ripple-keypairs/issues", + "source": "https://github.com/lessmore92/php-ripple-keypairs/tree/v1.0.0" + }, + "time": "2021-01-11T16:59:51+00:00" + }, + { + "name": "psr/http-client", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "22b2ef5687f43679481615605d7a15c557ce85b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/22b2ef5687f43679481615605d7a15c557ce85b1", + "reference": "22b2ef5687f43679481615605d7a15c557ce85b1", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, + "time": "2020-09-19T09:12:31+00:00" + }, + { + "name": "psr/http-message", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/efd67d1dc14a7ef4fc4e518e7dee91c271d524e4", + "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2019-08-29T13:16:46+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "simplito/bigint-wrapper-php", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/simplito/bigint-wrapper-php.git", + "reference": "cf21ec76d33f103add487b3eadbd9f5033a25930" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplito/bigint-wrapper-php/zipball/cf21ec76d33f103add487b3eadbd9f5033a25930", + "reference": "cf21ec76d33f103add487b3eadbd9f5033a25930", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "BI\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simplito Team", + "email": "s.smyczynski@simplito.com", + "homepage": "https://simplito.com" + } + ], + "description": "Common interface for php_gmp and php_bcmath modules", + "support": { + "issues": "https://github.com/simplito/bigint-wrapper-php/issues", + "source": "https://github.com/simplito/bigint-wrapper-php/tree/1.0.0" + }, + "time": "2018-02-27T12:38:08+00:00" + }, + { + "name": "simplito/bn-php", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/simplito/bn-php.git", + "reference": "e852fcd27e4acbc32459606d7606e45a85e42465" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplito/bn-php/zipball/e852fcd27e4acbc32459606d7606e45a85e42465", + "reference": "e852fcd27e4acbc32459606d7606e45a85e42465", + "shasum": "" + }, + "require": { + "simplito/bigint-wrapper-php": "~1.0.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "BN\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simplito Team", + "email": "s.smyczynski@simplito.com", + "homepage": "https://simplito.com" + } + ], + "description": "Big number implementation compatible with bn.js", + "support": { + "issues": "https://github.com/simplito/bn-php/issues", + "source": "https://github.com/simplito/bn-php/tree/1.1.2" + }, + "time": "2018-04-12T11:07:43+00:00" + }, + { + "name": "simplito/elliptic-php", + "version": "1.0.7", + "source": { + "type": "git", + "url": "https://github.com/simplito/elliptic-php.git", + "reference": "a2612c8289270bd00086d1c070efc3fca9d7abce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplito/elliptic-php/zipball/a2612c8289270bd00086d1c070efc3fca9d7abce", + "reference": "a2612c8289270bd00086d1c070efc3fca9d7abce", + "shasum": "" + }, + "require": { + "ext-gmp": "*", + "simplito/bn-php": "~1.1.0" + }, + "require-dev": { + "phpbench/phpbench": "@dev", + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Elliptic\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simplito Team", + "email": "s.smyczynski@simplito.com", + "homepage": "https://simplito.com" + } + ], + "description": "Fast elliptic curve cryptography", + "homepage": "https://github.com/simplito/elliptic-php", + "keywords": [ + "Curve25519", + "ECDSA", + "Ed25519", + "EdDSA", + "cryptography", + "curve", + "ecc", + "ecdh", + "elliptic", + "nistp192", + "nistp224", + "nistp256", + "nistp384", + "nistp521", + "secp256k1" + ], + "support": { + "issues": "https://github.com/simplito/elliptic-php/issues", + "source": "https://github.com/simplito/elliptic-php/tree/1.0.7" + }, + "time": "2021-01-12T11:40:37+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">7" + }, + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/src/Foundation/Contracts/HttpClientInterface.php b/src/Foundation/Contracts/HttpClientInterface.php new file mode 100644 index 0000000..ab58b0f --- /dev/null +++ b/src/Foundation/Contracts/HttpClientInterface.php @@ -0,0 +1,9 @@ +timeout = $timeout; + $this->baseUri = $baseUri; + $this->client = new Client([ + 'base_uri' => $this->baseUri, + 'timeout' => $this->timeout, + ]); + } + + /** + * @param HttpRequestInterface|Request $request + * @return HttpResponseInterface + * @throws GuzzleException + */ + public function send(HttpRequestInterface $request): HttpResponseInterface + { + $response = $this->client->request('POST', $request->getUrl(), [ + 'json' => $request->getBody() + ]); + + return new Response($response); + } + + public function setTimeOut(float $timeout): self + { + $this->timeout = $timeout; + return $this; + } +} diff --git a/src/GuzzleClient/Request.php b/src/GuzzleClient/Request.php new file mode 100644 index 0000000..9203f0a --- /dev/null +++ b/src/GuzzleClient/Request.php @@ -0,0 +1,63 @@ +url; + } + + public function setUrl(string $url) + { + $this->url = $url; + return $this; + } + + public function setJson(array $body) + { + $this->body = $body; + return $this; + } + + public function getBody() + { + return $this->body; + } + + public function setBody(string $body) + { + $this->body = $body; + return $this; + } + + public function getHeaders(): array + { + $headers = $this->headers; + if ($this->isJson) + { + $headers['Content-Type: application/json']; + } + return $headers; + } + + public function setHeaders(array $headers) + { + $this->headers = $headers; + return $this; + } + + public function isJson() + { + $this->isJson = true; + return $this; + } +} diff --git a/src/GuzzleClient/Response.php b/src/GuzzleClient/Response.php new file mode 100644 index 0000000..083846e --- /dev/null +++ b/src/GuzzleClient/Response.php @@ -0,0 +1,37 @@ +response = $response; + } + + public function getBody() + { + return $this->response->getBody() + ->getContents() + ; + } + + + public function getHeaders() + { + return $this->response->getHeaders(); + } + + public function getResponse(): ResponseInterface + { + $this->response; + } +} diff --git a/src/Model/Base/Balance.php b/src/Model/Base/Balance.php new file mode 100644 index 0000000..1a540d7 --- /dev/null +++ b/src/Model/Base/Balance.php @@ -0,0 +1,38 @@ +drops = $drops; + } + + public static function fromDrops($drops) + { + return new self($drops); + } + + public function toXrp() + { + return Utils::dropsToXrp($this->drops); + } + + public function __debugInfo() + { + return [ + 'drops' => $this->drops, + 'xrp' => Utils::dropsToXrp($this->drops), + ]; + } +} diff --git a/src/Model/Response/AccountInfo.php b/src/Model/Response/AccountInfo.php new file mode 100644 index 0000000..73509f9 --- /dev/null +++ b/src/Model/Response/AccountInfo.php @@ -0,0 +1,54 @@ +account = Utils::arrayGet($json, 'Account'); + $instance->balance = Balance::fromDrops(Utils::arrayGet($json, 'Balance', '')); + $instance->flags = Utils::arrayGet($json, 'Flags'); + $instance->ledgerEntryType = Utils::arrayGet($json, 'LedgerEntryType'); + $instance->ownerCount = Utils::arrayGet($json, 'OwnerCount'); + $instance->previousTxnID = Utils::arrayGet($json, 'PreviousTxnID'); + $instance->previousTxnLgrSeq = Utils::arrayGet($json, 'PreviousTxnLgrSeq'); + $instance->sequence = Utils::arrayGet($json, 'Sequence'); + $instance->index = Utils::arrayGet($json, 'index'); + + return $instance; + } +} diff --git a/src/RippleAPI.php b/src/RippleAPI.php new file mode 100644 index 0000000..9ba5dd2 --- /dev/null +++ b/src/RippleAPI.php @@ -0,0 +1,139 @@ +maxFeeXRP = isset($options['maxFeeXRP']) ? strval($options['maxFeeXRP']) : '2'; + + if (!isset($options['server'])) + { + throw new \Exception('Json RPC server not provided.'); + } + $this->server = $options['server']; + $this->timeout = isset($options['timeOut']) ? $options['timeOut'] : 3; + + if (is_null($http)) + { + $http = new Http($this->server, $this->timeout); + } + $this->http = $http; + } + + public function accountInfo(string $account, $strict = true, $ledgerIndex = "current", $queue = true) + { + return AccountInfo::fromJson($this->send('account_info', [ + 'account' => $account, + 'strict' => $strict, + 'ledger_index' => $ledgerIndex, + ' queue' => $queue, + ])['account_data']); + } + + public function send($method, $params = null) + { + $req = new Request(); + + $body['method'] = $method; + $body['params'] = [ + $params + ]; + + $req->setJson($body); + $res = $this->http->send($req); + + $json = json_decode($res->getBody(), true); + return $json['result']; + } + + public function accountTx(string $account, $options = []) + { + $options['account'] = $account; + + return $this->send('account_tx', $options); + } + + public function tx(string $transaction, bool $binary = false) + { + $options['transaction'] = $transaction; + + return $this->send('tx', $options); + } + + public function submit(string $tx_blob) + { + return $this->send('submit', ['tx_blob' => $tx_blob]); + } + + public function getFee($cushion = null) + { + if (is_null($cushion)) + { + $cushion = $this->feeCushion; + } + + if (is_null($cushion)) + { + $cushion = 1.2; + } + + $serverInfo = $this->serverInfo(); + $baseFeeXrp = $serverInfo['validated_ledger']['base_fee_xrp']; + $fee = $baseFeeXrp * $serverInfo['load_factor'] * $cushion; + + $fee = min($this->maxFeeXRP, $fee); + return number_format($fee, 6, '.', ''); + } + + public function serverInfo() + { + return Utils::arrayGet($this->send('server_info'), 'info'); + } + + public function sign(string $txJson, string $secret, array $options = []) + { + $tx = json_decode($txJson, true); + $this->checkFee($tx['Fee']); + $sign = new Sign(); + return $sign->sign($tx, $secret, $options); + } + + protected function checkFee(string $fee) + { + $fee = new BN($fee); + $maxFeeDrops = Utils::xrpToDrops($this->maxFeeXRP); + if ($fee->gt(new BN($maxFeeDrops))) + { + throw new \Exception("Fee should not exceed '{$maxFeeDrops}'. To use a higher fee, set 'maxFeeXRP' in the RippleAPI constructor."); + } + } +} diff --git a/src/Transaction/Sign.php b/src/Transaction/Sign.php new file mode 100644 index 0000000..eefb80c --- /dev/null +++ b/src/Transaction/Sign.php @@ -0,0 +1,98 @@ +keypair = new RippleKeyPairs(); + $this->binaryCodec = new RippleBinaryCodec(); + } + + public function sign($txJson, $secret, $options = []) + { + return $this->signWithKeypair($txJson, $this->keypair->deriveKeypair($secret), $options); + } + + public function signWithKeypair($txJson, $keypair, $options) + { + if (isset($txJson['TxnSignature']) || isset($txJson['Signers'])) + { + throw new Exception('txJSON must not contain "TxnSignature" or "Signers" properties'); + } + + //fee checking moved to Ripple.php + //$this->checkFee($txJson['fee']); + + $txToSignAndEncode = $txJson; + $txToSignAndEncode['SigningPubKey'] = isset($options['signAs']) ? '' : $keypair['public']; + + if (isset($options['signAs'])) + { + $signer['Account'] = $options['signAs']; + $signer['SigningPubKey'] = $keypair['public']; + $signer['TxnSignature'] = $this->computeSignature( + $txToSignAndEncode, + $keypair['private'], + $options['signAs'] + ); + $txToSignAndEncode['Signers'] = [['Signer' => $signer]]; + } + else + { + $txToSignAndEncode['TxnSignature'] = $this->computeSignature( + $txToSignAndEncode, + $keypair['private'] + ); + } + + $serialized = $this->binaryCodec->encode($txToSignAndEncode); + + return [ + 'signedTransaction' => $serialized, + 'id' => $this->computeBinaryTransactionHash($serialized) + ]; + } + + public function computeSignature(array $tx, string $privateKey, string $signAs = null) + { + $signingData = $signAs + ? $this->binaryCodec->encodeForMultisigning($tx, $signAs) + : $this->binaryCodec->encodeForSigning($tx); + + return $this->keypair->sign(Buffer::hex($signingData) + ->getBinary(), $privateKey); + } + + public function computeBinaryTransactionHash(string $serializedTx) + { + $prefix = Buffer::int(TRANSACTION_ID) + ->getHex() + ; + + return Buffer::hex(hash('sha512', Buffer::hex($prefix . $serializedTx) + ->getBinary())) + ->slice(0, 32) + ->getHex() + ; + } +} diff --git a/src/Utils.php b/src/Utils.php new file mode 100644 index 0000000..70ab585 --- /dev/null +++ b/src/Utils.php @@ -0,0 +1,74 @@ + 2) + { + throw new Exception("xrpToDrops: failed sanity check - value '${xrp}' has too many decimal points."); + } + + $fraction = isset($components[1]) ? $components[1] : '0'; + if (strlen($fraction) > 6) + { + throw new Exception("xrpToDrops: value '${xrp}' has too many decimal places."); + } + + return number_format($xrp * 1000000.0, 0, '', ''); + } + + public static function dropsToXrp($_drops) + { + if (!preg_match('/^-?[0-9]*\.?[0-9]*$/', $_drops)) + { + throw new Exception("dropsToXrp: invalid value '${_drops}', should be a number matching (^-?[0-9]*\.?[0-9]*$)."); + } + else if ($_drops === '.') + { + throw new Exception("dropsToXrp: invalid value '${_drops}', should be a string-encoded number."); + } + + if (strpos($_drops, '.') !== false) + { + throw new Exception("dropsToXrp: value '${_drops}' has too many decimal places."); + } + + if (!preg_match('/^-?[0-9]+$/', $_drops)) + { + throw new Exception("dropsToXrp: failed sanity check - value '${_drops}', does not match (^-?[0-9]+$)"); + } + + return $_drops / 1000000.0; + } + + public static function arrayGet(array $array, string $key, $default = null) + { + return isset($array[$key]) ? $array[$key] : $default; + } +}