diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..208dcfc --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.sh text eol=lf +tests/*.sh text eol=lf diff --git a/.gitignore b/.gitignore index 4c36e38..ef24815 100755 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -.idea/ -vendor/ +.idea/ +vendor/ +tests/.phpunit.result.cache diff --git a/CHANGELOG.md b/CHANGELOG.md index 61d048c..6e037d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +### 0.7.1 + +Enhancements and compatibility fixes + + - Added `Account::getPaymentOperations($sinceCursor = null, $limit = 50)` which returns only payment-like operations (`payment`, `path_payment`). Use this when you want to ignore `create_account` and `account_merge` records that also appear in Horizon's payments feed. `Account::getPayments()` remains unchanged and returns the heterogeneous feed. + - Standardized amount formatting at Stellar precision (7 decimal places): + - `StellarAmount::getScaledValue()` and `AssetAmount::getBalance()` return strings with 7 decimals. + - `Account::getNativeBalance()` returns a 7-decimal string (e.g., "0.0000000" when empty). + - Stroop accessors return integer strings (no decimals) and are recommended for arithmetic/comparison. + - PHP 8.3 / PHPUnit 9 compatibility: + - Replaced deprecated `@expectedException` annotations with `$this->expectException(...)`. + - `Xdr\\Type\\VariableArray` implements `Countable`. + - Declared `$size` on `Xdr\\XdrBuffer` (no dynamic property). + - Hardened `XdrModel\\Memo` validation to avoid null-related deprecations. + - Horizon behavior resilience: + - `Server::getAccount()` now detects JSON bodies with `status: 404` and returns `null` (previously could throw when certain Horizons didn’t raise exceptions). + - `ApiClient::postTransaction()` throws `PostTransactionException` on non-2xx (4xx) responses even when Guzzle exceptions are disabled. + - Integration test improvements: + - Tests skip gracefully when `STELLAR_HORIZON_BASE_URL` is not set. + - Base class auto-funds core fixtures (`basic1`, `basic2`, `basic3`) via friendbot and polls Horizon to avoid flakiness. + - Environment variables simplified: tests now use only `STELLAR_NETWORK_PASSPHRASE` (deprecated `STELLAR_NETWORK_PASSWORD`). + - Tooling/documentation: + - Normalized shell script line endings (LF) and added `.gitattributes` to enforce. + - README: documented payments feed vs. payment operations, amount formatting/precision, and integration environment setup. + ### 0.7.0 * Additional support for BumpSequenceOp: it is now read correctly when listing operations @@ -125,3 +150,4 @@ New Features ### 0.1.0 * Initial beta version + diff --git a/LICENSE b/LICENSE index ca4bfbe..3f03531 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2017 ZuluCrypto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2017 ZuluCrypto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/RELEASE_NOTES_v0.7.1.md b/RELEASE_NOTES_v0.7.1.md new file mode 100644 index 0000000..fb1cb07 --- /dev/null +++ b/RELEASE_NOTES_v0.7.1.md @@ -0,0 +1,31 @@ +Version 0.7.1 — Enhancements and compatibility fixes + +Highlights +- New API: `Account::getPaymentOperations()` returns only payment-like operations (payment, path_payment). Use when you want to ignore create_account and account_merge entries in Horizon’s mixed payments feed. `Account::getPayments()` remains the heterogeneous feed. +- Amount formatting standardized at Stellar precision (7 decimals) across display getters: + - `StellarAmount::getScaledValue()` and `AssetAmount::getBalance()` return 7-decimal strings + - `Account::getNativeBalance()` returns a 7-decimal string (e.g., "0.0000000" when empty) + - Stroop getters return integer strings for storage/comparison +- PHP 8.3 / PHPUnit 9 compatibility and deprecation fixes (Countable, dynamic properties, Memo validation, test annotations). +- Horizon error-handling resilience: JSON 404 handling for getAccount(); `postTransaction()` throws on non-2xx even with Guzzle exceptions disabled. +- Integration test UX: auto-fund core fixtures, graceful skipping; unified env var (`STELLAR_NETWORK_PASSPHRASE`). + +Breaking Changes +- None. `Account::getPayments()` remains unchanged; the new method provides a filtered alternative. + +Migration Notes +- Prefer `Account::getPaymentOperations()` when you only want payment/path_payment. +- Keep doing arithmetic in stroops (integer strings); use the 7-decimal display methods for presentation. +- Integration tests now expect: + - `STELLAR_HORIZON_BASE_URL` (e.g., http://localhost:8000/) + - `STELLAR_NETWORK_PASSPHRASE` (e.g., Integration Test Network ; zulucrypto) + - Note: `STELLAR_NETWORK_PASSWORD` is no longer used. + +Changelog Summary +- Add `Account::getPaymentOperations()` and unit tests +- Standardize amount formatting to 7 decimals; clarify PHPDocs +- Update PHPUnit 9 compatibility and fix PHP 8.3 deprecations +- Improve Horizon error handling for 404 JSON; throw on 4xx postTransaction +- Integration tests: auto-fund fixtures, skip without Horizon; use `STELLAR_NETWORK_PASSPHRASE` +- Normalize shell script line endings; docs on payments feed vs operations and amount precision + diff --git a/Readme.md b/Readme.md index abfb81d..05a164b 100644 --- a/Readme.md +++ b/Readme.md @@ -1,96 +1,150 @@ -## Description - -PHP Library for interacting with the Stellar network. - -* Communicate with Horizon server -* Build and sign transactions - -## :warning: Danger Zone :warning: - -**Development Status** - -This library is under active development and should be considered beta quality. -Please ensure that you've tested extensively on a test network and have added -sanity checks in other places in your code. - -:warning: [See the release notes for breaking changes](CHANGELOG.md) - -**Large Integer Support** - -The largest PHP integer is 64-bits when on a 64-bit platform. This is especially -important to pay attention to when working with large balance transfers. The native -representation of a single XLM (1 XLM) is 10000000 stroops. - -Therefore, if you try to use a `MAX_INT` number of XLM (or a custom asset) it is -possible to overflow PHP's integer type when the value is converted to stroops and -sent to the network. - -This library attempts to add checks for this scenario and also uses a `BigInteger` -class to work around this problem. - -If your application uses large amounts of XLM or a custom asset please do extensive -testing with large values and use the `StellarAmount` helper class or the `BigInteger` -class if possible. - -**Floating point issues** - -Although not specific to Stellar or PHP, it's important to be aware of problems -when doing comparisons between floating point numbers. +## Description + +PHP Library for interacting with the Stellar network. + +* Communicate with Horizon server +* Build and sign transactions + +## :warning: Danger Zone :warning: + +**Development Status** + +This library is under active development and should be considered beta quality. +Please ensure that you've tested extensively on a test network and have added +sanity checks in other places in your code. + +:warning: [See the release notes for breaking changes](CHANGELOG.md) + +**Large Integer Support** + +The largest PHP integer is 64-bits when on a 64-bit platform. This is especially +important to pay attention to when working with large balance transfers. The native +representation of a single XLM (1 XLM) is 10000000 stroops. + +Therefore, if you try to use a `MAX_INT` number of XLM (or a custom asset) it is +possible to overflow PHP's integer type when the value is converted to stroops and +sent to the network. + +This library attempts to add checks for this scenario and also uses a `BigInteger` +class to work around this problem. + +If your application uses large amounts of XLM or a custom asset please do extensive +testing with large values and use the `StellarAmount` helper class or the `BigInteger` +class if possible. + +**Floating point issues** + +Although not specific to Stellar or PHP, it's important to be aware of problems +when doing comparisons between floating point numbers. + +For example: + +```php +$oldBalance = 1.605; +$newBalance = 1.61; + +var_dump($oldBalance + 0.005); +var_dump($newBalance); +if ($oldBalance + 0.005 === $newBalance) { + print "Equal\n"; +} +else { + print "Not Equal\n"; +} +``` + +The above code considers the two values not to be equal even though the same value +is printed out: + +Output: +``` +float(1.61) +float(1.61) +Not Equal +``` + +To work around this issue, always work with and store amounts as an integer representing stroops. Only convert +back to a decimal number when you need to display a balance to the user. + +The static `StellarAmount::STROOP_SCALE` property can be used to help with this conversion. + +## Installation + +To install the latest release for usage in your project: + + cd your_project/ + composer require zulucrypto/stellar-api + +If you want to work with the most recent development version you can use this repository: + + git clone https://github.com/zulucrypto/stellar-api.git + cd stellar-api/ + composer install + +## Getting Started + +See the [getting-started](getting-started/) directory for examples of how to use this library. + +These examples are modeled after the ones in Stellar's getting started guide: + +https://www.stellar.org/developers/guides/get-started/create-account.html + +Additional examples are available in the [examples](examples/) directory -For example: +## Payments Feed vs. Payment Operations -```php -$oldBalance = 1.605; -$newBalance = 1.61; +Horizon’s `/accounts/{id}/payments` endpoint returns a mixed feed of records that are payment-related but include more than just payment operations. This library exposes two accessors on `Account`: -var_dump($oldBalance + 0.005); -var_dump($newBalance); -if ($oldBalance + 0.005 === $newBalance) { - print "Equal\n"; -} -else { - print "Not Equal\n"; -} -``` +- `Account::getPayments($sinceCursor = null, $limit = 50)` + - Returns the heterogeneous feed as-is, mapping each record to a typed model. + - Includes: `create_account`, `payment`, `account_merge`, and `path_payment`. -The above code considers the two values not to be equal even though the same value -is printed out: +- `Account::getPaymentOperations($sinceCursor = null, $limit = 50)` + - Returns only payment-like operations. + - Includes: `payment`, `path_payment`. + - Excludes: `create_account`, `account_merge`. -Output: -``` -float(1.61) -float(1.61) -Not Equal -``` +Use `getPaymentOperations()` when you only care about actual transfer operations and want to ignore account creations or merges that may also appear in the payments feed. -To work around this issue, always work with and store amounts as an integer representing stroops. Only convert -back to a decimal number when you need to display a balance to the user. +When running integration tests, set the following environment variables: -The static `StellarAmount::STROOP_SCALE` property can be used to help with this conversion. +- `STELLAR_HORIZON_BASE_URL` (e.g., `http://localhost:8000/`) +- `STELLAR_NETWORK_PASSPHRASE` (e.g., `Integration Test Network ; zulucrypto`) -## Installation +Note: `STELLAR_NETWORK_PASSWORD` is no longer used. -To install the latest release for usage in your project: +Examples (choose one set): - cd your_project/ - composer require zulucrypto/stellar-api +- Local integration network (Docker): + - `export STELLAR_HORIZON_BASE_URL=http://localhost:8000/` + - `export STELLAR_NETWORK_PASSPHRASE='Integration Test Network ; zulucrypto'` -If you want to work with the most recent development version you can use this repository: +- Stellar Testnet: + - `export STELLAR_HORIZON_BASE_URL=https://horizon-testnet.stellar.org/` + - `export STELLAR_NETWORK_PASSPHRASE='Test SDF Network ; September 2015'` - git clone https://github.com/zulucrypto/stellar-api.git - cd stellar-api/ - composer install +- Stellar Public Network: + - `export STELLAR_HORIZON_BASE_URL=https://horizon.stellar.org/` + - `export STELLAR_NETWORK_PASSPHRASE='Public Global Stellar Network ; September 2015'` -## Getting Started +## Amount Formatting and Precision -See the [getting-started](getting-started/) directory for examples of how to use this library. +Stellar amounts are precise to 7 decimal places (1 XLM = 10,000,000 stroops). This library follows that convention: -These examples are modeled after the ones in Stellar's getting started guide: +- Display values (scaled): + - `StellarAmount::getScaledValue()` → returns a string with 7 decimal places (e.g., `"12.3400000"`). + - `AssetAmount::getBalance()` → same 7-decimal string. + - `Account::getNativeBalance()` → 7-decimal string; returns `"0.0000000"` when empty. -https://www.stellar.org/developers/guides/get-started/create-account.html +- Storage/comparison values (stroops): + - `StellarAmount::getUnscaledString()` → integer string of stroops (e.g., `"123400000"`). + - `AssetAmount::getUnscaledBalance()` → stroops as an integer string. + - `Account::getNativeBalanceStroops()` → stroops as an integer string. -Additional examples are available in the [examples](examples/) directory +Guidance: +- Do arithmetic and comparisons using stroops whenever possible. +- Format for display using the 7-decimal methods above. ## Donations - -Stellar: GCUVDZRQ6CX347AMUUWZDYSNDFAWDN6FUYM5DVYYVO574NHTAUCQAK53 + +Stellar: GCUVDZRQ6CX347AMUUWZDYSNDFAWDN6FUYM5DVYYVO574NHTAUCQAK53 diff --git a/composer.json b/composer.json index fd685f2..91cfc0d 100755 --- a/composer.json +++ b/composer.json @@ -1,27 +1,28 @@ -{ - "name": "zulucrypto/stellar-api", - "description": "API client for the Stellar network", - "autoload": { - "psr-4": { - "ZuluCrypto\\StellarSdk\\": "src/", - "ZuluCrypto\\StellarSdk\\Test\\": "tests/" - } - }, +{ + "name": "zulucrypto/stellar-api", + "description": "API client for the Stellar network", + "autoload": { + "psr-4": { + "ZuluCrypto\\StellarSdk\\": "src/", + "ZuluCrypto\\StellarSdk\\Test\\": "tests/" + } + }, "require": { + "php": "^7.3 || ^8.0", "guzzlehttp/guzzle": "^6.2", "christian-riesen/base32": "^1.3", "paragonie/sodium_compat": "^1.0", - "phpseclib/phpseclib": "^2.0.6", + "phpseclib/phpseclib": "^3.0", "symfony/filesystem": "^4.1" - }, - "license": "MIT", - "authors": [ - { - "name": "Zulu Crypto", - "email": "zulucrypto@protonmail.com" - } - ], + }, + "license": "MIT", + "authors": [ + { + "name": "Zulu Crypto", + "email": "zulucrypto@protonmail.com" + } + ], "require-dev": { - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^9.6" } } diff --git a/composer.lock b/composer.lock index 2169a4f..2014888 100644 --- a/composer.lock +++ b/composer.lock @@ -1,36 +1,37 @@ { "_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#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "028fa7646668c51f7c7f0672d4fd3ab2", + "content-hash": "fa16969a72a646f5312be36605c86448", "packages": [ { "name": "christian-riesen/base32", - "version": "1.3.1", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/ChristianRiesen/base32.git", - "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa" + "reference": "2e82dab3baa008e24a505649b0d583c31d31e894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ChristianRiesen/base32/zipball/0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", - "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", + "url": "https://api.github.com/repos/ChristianRiesen/base32/zipball/2e82dab3baa008e24a505649b0d583c31d31e894", + "reference": "2e82dab3baa008e24a505649b0d583c31d31e894", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "4.*", - "satooshi/php-coveralls": "0.*" + "friendsofphp/php-cs-fixer": "^2.17", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^8.5.13 || ^9.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -58,31 +59,37 @@ "encode", "rfc4648" ], - "time": "2016-05-05T11:49:03+00:00" + "support": { + "issues": "https://github.com/ChristianRiesen/base32/issues", + "source": "https://github.com/ChristianRiesen/base32/tree/1.6.0" + }, + "time": "2021-02-26T10:19:33+00:00" }, { "name": "guzzlehttp/guzzle", - "version": "6.3.3", + "version": "6.5.8", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", - "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", "shasum": "" }, "require": { + "ext-json": "*", "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.4", - "php": ">=5.5" + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" }, "require-dev": { "ext-curl": "*", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", - "psr/log": "^1.0" + "psr/log": "^1.1" }, "suggest": { "psr/log": "Required for using the Log middleware" @@ -90,7 +97,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.3-dev" + "dev-master": "6.5-dev" } }, "autoload": { @@ -106,10 +113,40 @@ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle is a PHP HTTP client library", @@ -123,109 +160,176 @@ "rest", "web service" ], - "time": "2018-04-22T15:46:56+00:00" + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-20T22:16:07+00:00" }, { "name": "guzzlehttp/promises", - "version": "v1.3.1", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e", "shasum": "" }, "require": { - "php": ">=5.5.0" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "^4.0" + "symfony/phpunit-bridge": "^4.4 || ^5.1" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, "autoload": { - "psr-4": { - "GuzzleHttp\\Promise\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle promises library", "keywords": [ "promise" ], - "time": "2016-12-20T10:07:11+00:00" + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2023-05-21T12:31:43+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.4.2", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b", + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b", "shasum": "" }, "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0" + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, + "type": "library", "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, { "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", "homepage": "https://github.com/Tobion" } ], @@ -233,30 +337,118 @@ "keywords": [ "http", "message", + "psr-7", "request", "response", "stream", "uri", "url" ], - "time": "2017-03-20T17:10:46+00:00" + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-04-17T16:00:37+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.1.3", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "infection/infection": "^0", + "nikic/php-fuzzer": "^0", + "phpunit/phpunit": "^9|^10|^11", + "vimeo/psalm": "^4|^5|^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2025-09-24T15:06:41+00:00" }, { "name": "paragonie/random_compat", - "version": "v9.99.99", + "version": "v9.99.100", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", "shasum": "" }, "require": { - "php": "^7" + "php": ">= 7" }, "require-dev": { "phpunit/phpunit": "4.*|5.*", @@ -284,28 +476,33 @@ "pseudorandom", "random" ], - "time": "2018-07-02T15:55:56+00:00" + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" }, { "name": "paragonie/sodium_compat", - "version": "v1.6.3", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/paragonie/sodium_compat.git", - "reference": "7d0549c3947eaea620f4e523f42ab236cf7fd304" + "reference": "b938a5c6844d222a26d46a6c7b80291e4cd8cfab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/7d0549c3947eaea620f4e523f42ab236cf7fd304", - "reference": "7d0549c3947eaea620f4e523f42ab236cf7fd304", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/b938a5c6844d222a26d46a6c7b80291e4cd8cfab", + "reference": "b938a5c6844d222a26d46a6c7b80291e4cd8cfab", "shasum": "" }, "require": { "paragonie/random_compat": ">=1", - "php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7" + "php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7|^8" }, "require-dev": { - "phpunit/phpunit": "^3|^4|^5" + "phpunit/phpunit": "^3|^4|^5|^6|^7|^8|^9" }, "suggest": { "ext-libsodium": "PHP < 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security.", @@ -366,32 +563,36 @@ "secret-key cryptography", "side-channel resistant" ], - "time": "2018-06-06T17:30:29+00:00" + "support": { + "issues": "https://github.com/paragonie/sodium_compat/issues", + "source": "https://github.com/paragonie/sodium_compat/tree/v1.23.0" + }, + "time": "2025-10-06T08:53:07+00:00" }, { "name": "phpseclib/phpseclib", - "version": "2.0.11", + "version": "3.0.47", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b" + "reference": "9d6ca36a6c2dd434765b1071b2644a1c683b385d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/7053f06f91b3de78e143d430e55a8f7889efc08b", - "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/9d6ca36a6c2dd434765b1071b2644a1c683b385d", + "reference": "9d6ca36a6c2dd434765b1071b2644a1c683b385d", "shasum": "" }, "require": { - "php": ">=5.3.3" + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" }, "require-dev": { - "phing/phing": "~2.7", - "phpunit/phpunit": "^4.8.35|^5.7|^6.0", - "sami/sami": "~2.0", - "squizlabs/php_codesniffer": "~2.0" + "phpunit/phpunit": "*" }, "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", @@ -403,7 +604,7 @@ "phpseclib/bootstrap.php" ], "psr-4": { - "phpseclib\\": "phpseclib/" + "phpseclib3\\": "phpseclib/" } }, "notification-url": "https://packagist.org/downloads/", @@ -458,29 +659,47 @@ "x.509", "x509" ], - "time": "2018-04-15T16:55:05+00:00" + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.47" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2025-10-06T01:07:24+00:00" }, { "name": "psr/http-message", - "version": "1.0.1", + "version": "1.1", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -508,32 +727,75 @@ "request", "response" ], - "time": "2016-08-06T14:39:51+00:00" + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "time": "2023-04-04T09:50:52+00:00" }, { - "name": "symfony/filesystem", - "version": "v4.1.2", + "name": "ralouphie/getallheaders", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "562bf7005b55fd80d26b582d28e3e10f2dd5ae9c" + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/562bf7005b55fd80d26b582d28e3e10f2dd5ae9c", - "reference": "562bf7005b55fd80d26b582d28e3e10f2dd5ae9c", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", "shasum": "" }, "require": { - "php": "^7.1.3", - "symfony/polyfill-ctype": "~1.8" + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.1-dev" + "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": "symfony/filesystem", + "version": "v4.4.42", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "reference": "815412ee8971209bd4c1eecd5f4f481eacd44bf5", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" }, + "type": "library", "autoload": { "psr-4": { "Symfony\\Component\\Filesystem\\": "" @@ -556,53 +818,77 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Filesystem Component", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", - "time": "2018-05-30T07:26:09+00:00" + "support": { + "source": "https://github.com/symfony/filesystem/tree/v4.4.42" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-20T08:49:14+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.8.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.8-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -613,43 +899,63 @@ "polyfill", "portable" ], - "time": "2018-04-30T19:57:29+00:00" - } - ], - "packages-dev": [ + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { - "name": "doctrine/instantiator", - "version": "1.1.0", + "name": "symfony/polyfill-intl-idn", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" + "suggest": { + "ext-intl": "For best performance" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + "Symfony\\Polyfill\\Intl\\Idn\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -658,420 +964,568 @@ ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", "keywords": [ - "constructor", - "instantiate" + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2017-07-22T11:58:36+00:00" + "time": "2024-09-10T14:38:51+00:00" }, { - "name": "myclabs/deep-copy", - "version": "1.8.1", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.2" }, - "replace": { - "myclabs/deep-copy": "self.version" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "suggest": { + "ext-intl": "For best performance" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "DeepCopy\\": "src/DeepCopy/" + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, - "files": [ - "src/DeepCopy/deep_copy.php" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Create deep copies (clones) of your objects", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" ], - "time": "2018-06-11T23:09:50+00:00" + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" }, { - "name": "phar-io/manifest", - "version": "1.0.1", + "name": "symfony/polyfill-php80", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-phar": "*", - "phar-io/version": "^1.0.1", - "php": "^5.6 || ^7.0" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, "classmap": [ - "src/" + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" }, { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" - }, + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + } + ], + "packages-dev": [ { - "name": "phar-io/version", - "version": "1.0.1", + "name": "doctrine/instantiator", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" }, { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" } ], - "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { - "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "name": "myclabs/deep-copy", + "version": "1.13.4", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { - "php": ">=5.5" + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "DeepCopy\\": "src/DeepCopy/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" } ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2025-08-01T08:46:24+00:00" }, { - "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "name": "nikic/php-parser", + "version": "v5.6.2", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", - "webmozart/assert": "^1.0" + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" }, "require-dev": { - "doctrine/instantiator": "~1.0.5", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" }, + "bin": [ + "bin/php-parse" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "PhpParser\\": "lib/PhpParser" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "name": "Nikita Popov" } ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + }, + "time": "2025-10-21T19:32:17+00:00" }, { - "name": "phpdocumentor/type-resolver", - "version": "0.4.0", + "name": "phar-io/manifest", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "phpdocumentor/reflection-common": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "time": "2017-07-14T14:27:02+00:00" + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { - "name": "phpspec/prophecy", - "version": "1.7.6", + "name": "phar-io/version", + "version": "3.2.1", "source": { "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "php": "^7.2 || ^8.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7.x-dev" - } - }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" }, { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2018-04-18T13:57:24+00:00" + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "5.3.2", + "version": "9.2.32", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c89677919c5dd6d3b3852f230a663118762218ac", - "reference": "c89677919c5dd6d3b3852f230a663118762218ac", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-xmlwriter": "*", - "php": "^7.0", - "phpunit/php-file-iterator": "^1.4.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^2.0.1", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" + "nikic/php-parser": "^4.19.1 || ^5.1.0", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.6" }, "suggest": { - "ext-xdebug": "^2.5.5" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.3.x-dev" + "dev-main": "9.2.x-dev" } }, "autoload": { @@ -1097,29 +1551,43 @@ "testing", "xunit" ], - "time": "2018-04-06T15:36:58+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-22T04:23:01+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.5", + "version": "3.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1134,7 +1602,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1144,26 +1612,48 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "phpunit/php-invoker", + "version": "3.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -1180,37 +1670,47 @@ "role": "lead" } ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", "keywords": [ - "template" + "process" ], - "time": "2015-06-21T13:50:34+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" }, { - "name": "phpunit/php-timer", - "version": "1.0.9", + "name": "phpunit/php-text-template", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1225,42 +1725,51 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", "keywords": [ - "timer" + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2020-10-26T05:33:50+00:00" }, { - "name": "phpunit/php-token-stream", - "version": "2.0.2", + "name": "phpunit/php-timer", + "version": "5.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": "^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.2.4" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1275,65 +1784,73 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ - "tokenizer" + "timer" ], - "time": "2017-11-27T05:48:46+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" }, { "name": "phpunit/phpunit", - "version": "6.5.9", + "version": "9.6.29", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "093ca5508174cd8ab8efe44fd1dde447adfdec8f" + "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/093ca5508174cd8ab8efe44fd1dde447adfdec8f", - "reference": "093ca5508174cd8ab8efe44fd1dde447adfdec8f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", + "reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3", "shasum": "" }, "require": { + "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", - "php": "^7.0", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^5.3", - "phpunit/php-file-iterator": "^1.4.3", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^1.0.9", - "phpunit/phpunit-mock-objects": "^5.0.5", - "sebastian/comparator": "^2.1", - "sebastian/diff": "^2.0", - "sebastian/environment": "^3.1", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", - "sebastian/version": "^2.0.1" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2", - "phpunit/dbunit": "<3.0" - }, - "require-dev": { - "ext-pdo": "*" + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", + "sebastian/comparator": "^4.0.9", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.8", + "sebastian/global-state": "^5.0.8", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", + "sebastian/version": "^3.0.2" }, "suggest": { - "ext-xdebug": "*", - "phpunit/php-invoker": "^1.1" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -1341,10 +1858,13 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.5.x-dev" + "dev-master": "9.6-dev" } }, "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], "classmap": [ "src/" ] @@ -1367,41 +1887,115 @@ "testing", "xunit" ], - "time": "2018-07-03T06:40:40+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.29" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:29:11+00:00" }, { - "name": "phpunit/phpunit-mock-objects", - "version": "5.0.8", + "name": "sebastian/cli-parser", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "6f9a3c8bf34188a2b53ce2ae7a126089c53e0a9f" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/6f9a3c8bf34188a2b53ce2ae7a126089c53e0a9f", - "reference": "6f9a3c8bf34188a2b53ce2ae7a126089c53e0a9f", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.0", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.1" - }, - "conflict": { - "phpunit/phpunit": "<6.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.5" + "phpunit/phpunit": "^9.3" }, - "suggest": { - "ext-soap": "*" + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T06:27:43+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0.x-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -1420,38 +2014,101 @@ "role": "lead" } ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2018-07-13T03:27:23+00:00" + "time": "2020-10-26T13:08:54+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.1", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5", + "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1467,38 +2124,76 @@ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" } ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2025-08-10T06:51:50+00:00" }, { - "name": "sebastian/comparator", - "version": "2.1.3", + "name": "sebastian/complexity", + "version": "2.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/diff": "^2.0 || ^3.0", - "sebastian/exporter": "^3.1" + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1511,56 +2206,51 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2018-02-01T13:46:46+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", - "version": "2.0.1", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", - "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { - "php": "^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1573,46 +2263,62 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], "description": "Diff implementation", "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "diff" + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", - "version": "3.1.0", + "version": "5.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { - "php": "^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.1" + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -1637,34 +2343,44 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c", + "reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1677,6 +2393,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -1685,46 +2405,67 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:03:27+00:00" }, { "name": "sebastian/global-state", - "version": "2.0.0", + "version": "5.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6", + "reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6", "shasum": "" }, "require": { - "php": "^7.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "ext-dom": "*", + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-uopz": "*" @@ -1732,7 +2473,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1755,34 +2496,113 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" + } + ], + "time": "2025-08-10T07:10:35+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", - "version": "3.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1802,32 +2622,42 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" }, { "name": "sebastian/object-reflector", - "version": "1.1.1", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "773f97c67f28de00d397be301821b06708fca0be" + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", - "reference": "773f97c67f28de00d397be301821b06708fca0be", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": "^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1847,32 +2677,42 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" }, { "name": "sebastian/recursion-context", - "version": "3.0.0", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0", + "reference": "539c6691e0623af6dc6f9c20384c120f963465a0", "shasum": "" }, "require": { - "php": "^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1885,44 +2725,69 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, { "name": "Adam Harvey", "email": "aharvey@php.net" } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2025-08-10T06:57:39+00:00" }, { "name": "sebastian/resource-operations", - "version": "1.0.0", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-main": "3.0-dev" } }, "autoload": { @@ -1942,29 +2807,41 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "support": { + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-14T16:00:52+00:00" }, { - "name": "sebastian/version", - "version": "2.0.1", + "name": "sebastian/type", + "version": "3.2.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -1983,31 +2860,43 @@ "role": "lead" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" }, { - "name": "theseer/tokenizer", - "version": "1.1.0", + "name": "sebastian/version", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.0" + "php": ">=7.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -2019,63 +2908,74 @@ ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" }, { - "name": "webmozart/assert", - "version": "1.3.0", + "name": "theseer/tokenizer", + "version": "1.3.1", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + "url": "https://github.com/theseer/tokenizer.git", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" } ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } ], - "time": "2018-01-29T19:49:41+00:00" + "time": "2025-11-17T20:03:58+00:00" } ], "aliases": [], @@ -2083,6 +2983,9 @@ "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, - "platform": [], - "platform-dev": [] + "platform": { + "php": "^7.3 || ^8.0" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" } diff --git a/examples/account-exists.php b/examples/account-exists.php index a62dcc4..bfab7b2 100644 --- a/examples/account-exists.php +++ b/examples/account-exists.php @@ -1,32 +1,32 @@ -accountExists('GCP6IHMHWRCF5TQ4ZP6TVIRNDZD56W42F42VHYWMVDGDAND75YGAHHBQ'); - - if ($exists) { - print "Account exists!" . PHP_EOL; - } - else { - print "Account does not exist." . PHP_EOL; - } -} -// If there's an exception it could be a temporary error, like a connection issue -// to Horizon, so we cannot tell for sure if the account exists or not -catch (\Exception $e) { - print "Error: " . $e->getMessage() . PHP_EOL; -} +accountExists('GCP6IHMHWRCF5TQ4ZP6TVIRNDZD56W42F42VHYWMVDGDAND75YGAHHBQ'); + + if ($exists) { + print "Account exists!" . PHP_EOL; + } + else { + print "Account does not exist." . PHP_EOL; + } +} +// If there's an exception it could be a temporary error, like a connection issue +// to Horizon, so we cannot tell for sure if the account exists or not +catch (\Exception $e) { + print "Error: " . $e->getMessage() . PHP_EOL; +} diff --git a/examples/add-signer.php b/examples/add-signer.php index 64aa273..ad81865 100644 --- a/examples/add-signer.php +++ b/examples/add-signer.php @@ -1,38 +1,38 @@ -setMasterWeight(10); - -$signerKey = SignerKey::fromKeypair($newSigner); -$newAccountSigner = new Signer($signerKey, 1); -$optionsOperation->updateSigner($newAccountSigner); - -// Submit to the network -$server->buildTransaction($currentAccount->getPublicKey()) - ->addOperation($optionsOperation) +setMasterWeight(10); + +$signerKey = SignerKey::fromKeypair($newSigner); +$newAccountSigner = new Signer($signerKey, 1); +$optionsOperation->updateSigner($newAccountSigner); + +// Submit to the network +$server->buildTransaction($currentAccount->getPublicKey()) + ->addOperation($optionsOperation) ->submit($currentAccount->getSecret()); \ No newline at end of file diff --git a/examples/bump-sequence.php b/examples/bump-sequence.php index 93c4639..82046aa 100644 --- a/examples/bump-sequence.php +++ b/examples/bump-sequence.php @@ -1,24 +1,24 @@ -buildTransaction($currentAccount->getPublicKey()) - ->bumpSequenceTo(new BigInteger('47061756253569030')) +buildTransaction($currentAccount->getPublicKey()) + ->bumpSequenceTo(new BigInteger('47061756253569030')) ->submit($currentAccount->getSecret()); \ No newline at end of file diff --git a/examples/manage-data.php b/examples/manage-data.php index 6a4106d..e0f5194 100644 --- a/examples/manage-data.php +++ b/examples/manage-data.php @@ -1,20 +1,20 @@ -buildTransaction($keypair) - ->setAccountData('color', 'blue') - ->submit($keypair); - - -printf("Data updated." . PHP_EOL); +buildTransaction($keypair) + ->setAccountData('color', 'blue') + ->submit($keypair); + + +printf("Data updated." . PHP_EOL); printf("View account at: %saccounts/%s" . PHP_EOL, $server->getHorizonBaseUrl(), $keypair->getPublicKey()); \ No newline at end of file diff --git a/examples/manage-offer.php b/examples/manage-offer.php index 01e58f9..8407e2e 100644 --- a/examples/manage-offer.php +++ b/examples/manage-offer.php @@ -1,42 +1,42 @@ -getPublicKey()); -$nativeAsset = Asset::newNativeAsset(); - -// Offer 5,000 XLM @ 100 XLM per 1 USDTEST -$server->buildTransaction($offeringKeypair->getPublicKey()) - ->addOperation( - new \ZuluCrypto\StellarSdk\XdrModel\Operation\ManageOfferOp( - $usdtestAsset, - $nativeAsset, - 5000, - new \ZuluCrypto\StellarSdk\XdrModel\Price(100, 1) - ) - ) - ->submit($offeringKeypair->getSecret()); - -// Passive offer of 1,000 XLM @ 50 XLM per 1 USDTEST -$server->buildTransaction($offeringKeypair->getPublicKey()) - ->addOperation( - new \ZuluCrypto\StellarSdk\XdrModel\Operation\CreatePassiveOfferOp( - $usdtestAsset, - $nativeAsset, - 1000, - new \ZuluCrypto\StellarSdk\XdrModel\Price(50, 1) - ) - ) +getPublicKey()); +$nativeAsset = Asset::newNativeAsset(); + +// Offer 5,000 XLM @ 100 XLM per 1 USDTEST +$server->buildTransaction($offeringKeypair->getPublicKey()) + ->addOperation( + new \ZuluCrypto\StellarSdk\XdrModel\Operation\ManageOfferOp( + $usdtestAsset, + $nativeAsset, + 5000, + new \ZuluCrypto\StellarSdk\XdrModel\Price(100, 1) + ) + ) + ->submit($offeringKeypair->getSecret()); + +// Passive offer of 1,000 XLM @ 50 XLM per 1 USDTEST +$server->buildTransaction($offeringKeypair->getPublicKey()) + ->addOperation( + new \ZuluCrypto\StellarSdk\XdrModel\Operation\CreatePassiveOfferOp( + $usdtestAsset, + $nativeAsset, + 1000, + new \ZuluCrypto\StellarSdk\XdrModel\Price(50, 1) + ) + ) ->submit($offeringKeypair->getSecret()); \ No newline at end of file diff --git a/examples/merge-account.php b/examples/merge-account.php index 8adc186..4dbd461 100644 --- a/examples/merge-account.php +++ b/examples/merge-account.php @@ -1,24 +1,24 @@ -fundAccount($fromKeypair); -$server->fundAccount($destinationKeypair); - -// Transfer balance from $fromKeypair to $destinationKeypair - -$server->buildTransaction($fromKeypair) - ->addMergeOperation($destinationKeypair) +fundAccount($fromKeypair); +$server->fundAccount($destinationKeypair); + +// Transfer balance from $fromKeypair to $destinationKeypair + +$server->buildTransaction($fromKeypair) + ->addMergeOperation($destinationKeypair) ->submit($fromKeypair); \ No newline at end of file diff --git a/examples/mnemonic-address.php b/examples/mnemonic-address.php index f596f17..8927aac 100644 --- a/examples/mnemonic-address.php +++ b/examples/mnemonic-address.php @@ -1,20 +1,20 @@ -getPublicKey() . PHP_EOL; -// SAFWTGXVS7ELMNCXELFWCFZOPMHUZ5LXNBGUVRCY3FHLFPXK4QPXYP2X +getPublicKey() . PHP_EOL; +// SAFWTGXVS7ELMNCXELFWCFZOPMHUZ5LXNBGUVRCY3FHLFPXK4QPXYP2X print "Seed : " . $primaryAccount->getSecret() . PHP_EOL; \ No newline at end of file diff --git a/examples/payment-transaction.php b/examples/payment-transaction.php index 374c9ca..f59a6dd 100644 --- a/examples/payment-transaction.php +++ b/examples/payment-transaction.php @@ -1,33 +1,33 @@ -buildTransaction($sourceKeypair) - ->addLumenPayment($destinationKeypair, 10) - ->getTransactionEnvelope(); - -$txEnvelope->sign($sourceKeypair); - -$b64Tx = base64_encode($txEnvelope->toXdr()); - -print "Submitting transaction: " . PHP_EOL; -print $b64Tx; -print PHP_EOL; - -$server->submitB64Transaction($b64Tx); - +buildTransaction($sourceKeypair) + ->addLumenPayment($destinationKeypair, 10) + ->getTransactionEnvelope(); + +$txEnvelope->sign($sourceKeypair); + +$b64Tx = base64_encode($txEnvelope->toXdr()); + +print "Submitting transaction: " . PHP_EOL; +print $b64Tx; +print PHP_EOL; + +$server->submitB64Transaction($b64Tx); + diff --git a/examples/set-options.php b/examples/set-options.php index 23865b9..043c9f9 100644 --- a/examples/set-options.php +++ b/examples/set-options.php @@ -1,50 +1,50 @@ -setInflationDestination('GBLGN5K633LO5BMWEKSVHKXTPZHBVVBNSXRGXRDGZUANXWQ4LBWES3BK'); - -// Set auth required -$optionsOperation->setAuthRequired(true); - -// Set auth revokable -$optionsOperation->setAuthRevocable(true); - -// Add a new account as a signer (GAJCCCRIRXAYEU2ATNQAFYH4E2HKLN2LCKM2VPXCTJKIBVTRSOLEGCJZ) -$newSignerKeypair = Keypair::newFromSeed('SDJCZISO5M5XAUV6Y7MZJNN3JZ5BWPXDHV4GXP3MYNACVDNQRQSERXBC'); -$signerKey = SignerKey::fromKeypair($newSignerKeypair); -$newAccountSigner = new Signer($signerKey, 5); - -$optionsOperation->updateSigner($newAccountSigner); - -// Set weight of the master key -$optionsOperation->setMasterWeight(255); - -// Set threshold values -$optionsOperation->setLowThreshold(1); -$optionsOperation->setMediumThreshold(2); -$optionsOperation->setHighThreshold(3); - -// Set home domain -$optionsOperation->setHomeDomain('example.com'); - - -// Submit options to the network -$server->buildTransaction($keypair->getPublicKey()) - ->addOperation($optionsOperation) +setInflationDestination('GBLGN5K633LO5BMWEKSVHKXTPZHBVVBNSXRGXRDGZUANXWQ4LBWES3BK'); + +// Set auth required +$optionsOperation->setAuthRequired(true); + +// Set auth revokable +$optionsOperation->setAuthRevocable(true); + +// Add a new account as a signer (GAJCCCRIRXAYEU2ATNQAFYH4E2HKLN2LCKM2VPXCTJKIBVTRSOLEGCJZ) +$newSignerKeypair = Keypair::newFromSeed('SDJCZISO5M5XAUV6Y7MZJNN3JZ5BWPXDHV4GXP3MYNACVDNQRQSERXBC'); +$signerKey = SignerKey::fromKeypair($newSignerKeypair); +$newAccountSigner = new Signer($signerKey, 5); + +$optionsOperation->updateSigner($newAccountSigner); + +// Set weight of the master key +$optionsOperation->setMasterWeight(255); + +// Set threshold values +$optionsOperation->setLowThreshold(1); +$optionsOperation->setMediumThreshold(2); +$optionsOperation->setHighThreshold(3); + +// Set home domain +$optionsOperation->setHomeDomain('example.com'); + + +// Submit options to the network +$server->buildTransaction($keypair->getPublicKey()) + ->addOperation($optionsOperation) ->submit($keypair->getSecret()); \ No newline at end of file diff --git a/examples/sign-message.php b/examples/sign-message.php index e2f6a39..00d3f58 100644 --- a/examples/sign-message.php +++ b/examples/sign-message.php @@ -1,28 +1,28 @@ -sign($message); - -printf("Signed (base-64 encoded): " . base64_encode($signatureBytes) . PHP_EOL); - - -// Verify the signature -// Note that only the public key is required -$verifyingKeypair = Keypair::newFromPublicKey('GDRXE2BQUC3AZNPVFSCEZ76NJ3WWL25FYFK6RGZGIEKWE4SOOHSUJUJ6'); - -$isVerified = $verifyingKeypair->verifySignature($signatureBytes, $message); -printf(PHP_EOL); +sign($message); + +printf("Signed (base-64 encoded): " . base64_encode($signatureBytes) . PHP_EOL); + + +// Verify the signature +// Note that only the public key is required +$verifyingKeypair = Keypair::newFromPublicKey('GDRXE2BQUC3AZNPVFSCEZ76NJ3WWL25FYFK6RGZGIEKWE4SOOHSUJUJ6'); + +$isVerified = $verifyingKeypair->verifySignature($signatureBytes, $message); +printf(PHP_EOL); printf("Verified? %s" . PHP_EOL, ($isVerified) ? 'Yes' : 'No'); \ No newline at end of file diff --git a/examples/stream-effects.php b/examples/stream-effects.php index 4278ae2..328ad03 100644 --- a/examples/stream-effects.php +++ b/examples/stream-effects.php @@ -1,16 +1,16 @@ -streamEffects('now', function(Effect $effect) { - printf('[%s] %s' . PHP_EOL, - (new \DateTime())->format('Y-m-d h:i:sa'), - $effect->getType() - ); -}); - +streamEffects('now', function(Effect $effect) { + printf('[%s] %s' . PHP_EOL, + (new \DateTime())->format('Y-m-d h:i:sa'), + $effect->getType() + ); +}); + diff --git a/examples/stream-ledgers.php b/examples/stream-ledgers.php index 38fd51b..dcf9611 100644 --- a/examples/stream-ledgers.php +++ b/examples/stream-ledgers.php @@ -1,17 +1,17 @@ -streamLedgers('now', function(Ledger $ledger) { - printf('[%s] Closed %s at %s with %s operations' . PHP_EOL, - (new \DateTime())->format('Y-m-d h:i:sa'), - $ledger->getId(), - $ledger->getClosedAt()->format('Y-m-d h:i:sa'), - $ledger->getOperationCount() - ); -}); +streamLedgers('now', function(Ledger $ledger) { + printf('[%s] Closed %s at %s with %s operations' . PHP_EOL, + (new \DateTime())->format('Y-m-d h:i:sa'), + $ledger->getId(), + $ledger->getClosedAt()->format('Y-m-d h:i:sa'), + $ledger->getOperationCount() + ); +}); diff --git a/examples/stream-operations.php b/examples/stream-operations.php index ccfda09..5b90b91 100644 --- a/examples/stream-operations.php +++ b/examples/stream-operations.php @@ -1,16 +1,16 @@ -streamOperations('now', function(Operation $operation) { - printf('[%s] %s' . PHP_EOL, - (new \DateTime())->format('Y-m-d h:i:sa'), - $operation->getType() - ); -}); - +streamOperations('now', function(Operation $operation) { + printf('[%s] %s' . PHP_EOL, + (new \DateTime())->format('Y-m-d h:i:sa'), + $operation->getType() + ); +}); + diff --git a/examples/stream-payments.php b/examples/stream-payments.php index 84137b5..cfb4baf 100644 --- a/examples/stream-payments.php +++ b/examples/stream-payments.php @@ -1,19 +1,19 @@ -streamPayments('now', function(AssetTransferInterface $assetTransfer) { - printf('[%s] [%s] %s from %s -> %s' . PHP_EOL, - (new \DateTime())->format('Y-m-d h:i:sa'), - $assetTransfer->getAssetTransferType(), - $assetTransfer->getAssetAmount(), - $assetTransfer->getFromAccountId(), - $assetTransfer->getToAccountId() - ); -}); - +streamPayments('now', function(AssetTransferInterface $assetTransfer) { + printf('[%s] [%s] %s from %s -> %s' . PHP_EOL, + (new \DateTime())->format('Y-m-d h:i:sa'), + $assetTransfer->getAssetTransferType(), + $assetTransfer->getAssetAmount(), + $assetTransfer->getFromAccountId(), + $assetTransfer->getToAccountId() + ); +}); + diff --git a/examples/stream-transactions.php b/examples/stream-transactions.php index 3915606..45097ce 100644 --- a/examples/stream-transactions.php +++ b/examples/stream-transactions.php @@ -1,17 +1,17 @@ -streamTransactions('now', function(Transaction $transaction) { - printf('[%s] Transaction #%s with memo %s' . PHP_EOL, - (new \DateTime())->format('Y-m-d h:i:sa'), - $transaction->getId(), - $transaction->getMemo() - ); -}); - +streamTransactions('now', function(Transaction $transaction) { + printf('[%s] Transaction #%s with memo %s' . PHP_EOL, + (new \DateTime())->format('Y-m-d h:i:sa'), + $transaction->getId(), + $transaction->getMemo() + ); +}); + diff --git a/examples/transaction-add-signature.php b/examples/transaction-add-signature.php index aa37063..5feb346 100644 --- a/examples/transaction-add-signature.php +++ b/examples/transaction-add-signature.php @@ -1,55 +1,55 @@ -sign($payingKeypair, $server); - - -// TransactionEnvelope now has two signatures and can be submitted -$server->submitB64Transaction($transactionEnvelope->toBase64()); - +sign($payingKeypair, $server); + + +// TransactionEnvelope now has two signatures and can be submitted +$server->submitB64Transaction($transactionEnvelope->toBase64()); + print "Done!" . PHP_EOL; \ No newline at end of file diff --git a/examples/transaction-result.php b/examples/transaction-result.php index baca149..7053552 100644 --- a/examples/transaction-result.php +++ b/examples/transaction-result.php @@ -1,70 +1,70 @@ -buildTransaction($sourceKeypair) - ->addCreateAccountOp($newAccount1, 5) - ->addCreateAccountOp($newAccount2, 5) - ->submit($sourceKeypair); - -/* - * Get information on the overall result of the transaction - */ -/** @var \ZuluCrypto\StellarSdk\XdrModel\TransactionResult $result */ -$result = $response->getResult(); - -print "Fee charged: " . $result->getFeeCharged()->getScaledValue() . " XLM" . PHP_EOL; - - -/* - * Each operation within the transaction has its own result - */ -$operationResults = $result->getOperationResults(); - -/* - * Each result will be a child class of OperationResult depending on what the - * original operation was. - * - * See these classes for additional details that can be retrieved for each type - * of result - */ -foreach ($operationResults as $operationResult) { - print "Operation result is a: " . get_class($operationResult) . PHP_EOL; -} - -/* - * Exception handling - */ - -// This transaction will fail because there aren't enough lumens in the source -// account -try { - $response = $server->buildTransaction($sourceKeypair) - ->addLumenPayment($newAccount1, 9999999) - ->submit($sourceKeypair); -} catch (PostTransactionException $e) { - // Details operation information can be retrieved from this exception - $operationResults = $e->getResult()->getOperationResults(); - - foreach ($operationResults as $result) { - // Skip through the ones that worked - if ($result->succeeded()) continue; - - // Print out the first failed one - print "Operation failed with code: " . $result->getErrorCode() . PHP_EOL; - } -} +buildTransaction($sourceKeypair) + ->addCreateAccountOp($newAccount1, 5) + ->addCreateAccountOp($newAccount2, 5) + ->submit($sourceKeypair); + +/* + * Get information on the overall result of the transaction + */ +/** @var \ZuluCrypto\StellarSdk\XdrModel\TransactionResult $result */ +$result = $response->getResult(); + +print "Fee charged: " . $result->getFeeCharged()->getScaledValue() . " XLM" . PHP_EOL; + + +/* + * Each operation within the transaction has its own result + */ +$operationResults = $result->getOperationResults(); + +/* + * Each result will be a child class of OperationResult depending on what the + * original operation was. + * + * See these classes for additional details that can be retrieved for each type + * of result + */ +foreach ($operationResults as $operationResult) { + print "Operation result is a: " . get_class($operationResult) . PHP_EOL; +} + +/* + * Exception handling + */ + +// This transaction will fail because there aren't enough lumens in the source +// account +try { + $response = $server->buildTransaction($sourceKeypair) + ->addLumenPayment($newAccount1, 9999999) + ->submit($sourceKeypair); +} catch (PostTransactionException $e) { + // Details operation information can be retrieved from this exception + $operationResults = $e->getResult()->getOperationResults(); + + foreach ($operationResults as $result) { + // Skip through the ones that worked + if ($result->succeeded()) continue; + + // Print out the first failed one + print "Operation failed with code: " . $result->getErrorCode() . PHP_EOL; + } +} diff --git a/examples/transaction-set-sequence-number.php b/examples/transaction-set-sequence-number.php index 6bfa970..5d23ae8 100644 --- a/examples/transaction-set-sequence-number.php +++ b/examples/transaction-set-sequence-number.php @@ -1,25 +1,25 @@ -buildTransaction($sourceKeypair) - ->addLumenPayment($destinationKeypair, 100); - -$builder->setSequenceNumber(new BigInteger(123)); - +buildTransaction($sourceKeypair) + ->addLumenPayment($destinationKeypair, 100); + +$builder->setSequenceNumber(new BigInteger(123)); + print "Sequence number: " . $builder->getSequenceNumber() . "\n"; \ No newline at end of file diff --git a/examples/trust-asset.php b/examples/trust-asset.php index 3c638d1..ab8e40c 100644 --- a/examples/trust-asset.php +++ b/examples/trust-asset.php @@ -1,62 +1,62 @@ -getPublicKey()); - - -// First, the receiving account must add a trustline for the issuer -$server->buildTransaction($receivingKeypair) - ->addChangeTrustOp($asset) // this will default to the maximum value - ->submit($receivingKeypair); - -// Then, the issuing account can transfer assets -$server->buildTransaction($issuingKeypair) - ->addCustomAssetPaymentOp($asset, 50, $receivingKeypair->getPublicKey()) - ->submit($issuingKeypair->getSecret()); - - -// ------------------------------------ -// An asset that requires authorization - -// GDYW5Y5PCHC3RGUPME4MIFBQCDLFMCSFEB6EAA7P2PJRAKGPGUDZX64Q -$issuingKeypair = Keypair::newFromSeed('SC5AQ5K332ZIZB5MWG7FA64JURJXOR4B7VAIDIV7ORIEV7LSGNYFNPL3'); - -$asset = Asset::newCustomAsset('AUTHTEST', $issuingKeypair->getPublicKey()); - -// Issuing keypair indicates that authorization is required and revocable -$accountOptions = new SetOptionsOp(); -$accountOptions->setAuthRequired(true); -$accountOptions->setAuthRevocable(true); // This is optional - -$server->buildTransaction($issuingKeypair) - ->addOperation($accountOptions) - ->submit($issuingKeypair); - -// Receiving account adds a trustline -$server->buildTransaction($receivingKeypair->getPublicKey()) - ->addChangeTrustOp($asset) - ->submit($receivingKeypair->getSecret()); - -// Issuing account indicates the receiving account is authorized -$server->buildTransaction($issuingKeypair->getPublicKey()) - ->authorizeTrustline($asset, $receivingKeypair) - ->submit($issuingKeypair); - -// Issuing account can now transfer to receiving account -$server->buildTransaction($issuingKeypair) - ->addCustomAssetPaymentOp($asset, 75, $receivingKeypair->getPublicKey()) +getPublicKey()); + + +// First, the receiving account must add a trustline for the issuer +$server->buildTransaction($receivingKeypair) + ->addChangeTrustOp($asset) // this will default to the maximum value + ->submit($receivingKeypair); + +// Then, the issuing account can transfer assets +$server->buildTransaction($issuingKeypair) + ->addCustomAssetPaymentOp($asset, 50, $receivingKeypair->getPublicKey()) + ->submit($issuingKeypair->getSecret()); + + +// ------------------------------------ +// An asset that requires authorization + +// GDYW5Y5PCHC3RGUPME4MIFBQCDLFMCSFEB6EAA7P2PJRAKGPGUDZX64Q +$issuingKeypair = Keypair::newFromSeed('SC5AQ5K332ZIZB5MWG7FA64JURJXOR4B7VAIDIV7ORIEV7LSGNYFNPL3'); + +$asset = Asset::newCustomAsset('AUTHTEST', $issuingKeypair->getPublicKey()); + +// Issuing keypair indicates that authorization is required and revocable +$accountOptions = new SetOptionsOp(); +$accountOptions->setAuthRequired(true); +$accountOptions->setAuthRevocable(true); // This is optional + +$server->buildTransaction($issuingKeypair) + ->addOperation($accountOptions) + ->submit($issuingKeypair); + +// Receiving account adds a trustline +$server->buildTransaction($receivingKeypair->getPublicKey()) + ->addChangeTrustOp($asset) + ->submit($receivingKeypair->getSecret()); + +// Issuing account indicates the receiving account is authorized +$server->buildTransaction($issuingKeypair->getPublicKey()) + ->authorizeTrustline($asset, $receivingKeypair) + ->submit($issuingKeypair); + +// Issuing account can now transfer to receiving account +$server->buildTransaction($issuingKeypair) + ->addCustomAssetPaymentOp($asset, 75, $receivingKeypair->getPublicKey()) ->submit($issuingKeypair->getSecret()); \ No newline at end of file diff --git a/getting-started/01-create-account.php b/getting-started/01-create-account.php index f092601..a7e6b8e 100755 --- a/getting-started/01-create-account.php +++ b/getting-started/01-create-account.php @@ -1,13 +1,13 @@ -getSecret() . PHP_EOL; -// SAV76USXIJOBMEQXPANUOQM6F5LIOTLPDIDVRJBFFE2MDJXG24TAPUU7 - -print $keypair->getPublicKey() . PHP_EOL; +getSecret() . PHP_EOL; +// SAV76USXIJOBMEQXPANUOQM6F5LIOTLPDIDVRJBFFE2MDJXG24TAPUU7 + +print $keypair->getPublicKey() . PHP_EOL; // GCFXHS4GXL6BVUCXBWXGTITROWLVYXQKQLF4YH5O5JT3YZXCYPAFBJZB \ No newline at end of file diff --git a/getting-started/02-fund-account.php b/getting-started/02-fund-account.php index a3c2451..1e61e5d 100755 --- a/getting-started/02-fund-account.php +++ b/getting-started/02-fund-account.php @@ -1,15 +1,15 @@ -getAccount($publicAccountId); - -print 'Balances for account ' . $publicAccountId . PHP_EOL; - -foreach ($account->getBalances() as $balance) { - printf(' Type: %s, Code: %s, Balance: %s' . PHP_EOL, - $balance->getAssetType(), - $balance->getAssetCode(), - $balance->getBalance() - ); -} - +getAccount($publicAccountId); + +print 'Balances for account ' . $publicAccountId . PHP_EOL; + +foreach ($account->getBalances() as $balance) { + printf(' Type: %s, Code: %s, Balance: %s' . PHP_EOL, + $balance->getAssetType(), + $balance->getAssetCode(), + $balance->getBalance() + ); +} + diff --git a/getting-started/04-submit-transaction.php b/getting-started/04-submit-transaction.php index 7a9712e..972e6bb 100755 --- a/getting-started/04-submit-transaction.php +++ b/getting-started/04-submit-transaction.php @@ -1,36 +1,36 @@ -getAccount($destinationAccountId); - -// Build the payment transaction -$transaction = \ZuluCrypto\StellarSdk\Server::testNet() - ->buildTransaction($sourceKeypair->getPublicKey()) - ->addOperation( - PaymentOp::newNativePayment($destinationAccountId, 1) - ) -; - -// Sign and submit the transaction -$response = $transaction->submit($sourceKeypair->getSecret()); - -print "Response:" . PHP_EOL; -print_r($response->getRawData()); - -print PHP_EOL; +getAccount($destinationAccountId); + +// Build the payment transaction +$transaction = \ZuluCrypto\StellarSdk\Server::testNet() + ->buildTransaction($sourceKeypair->getPublicKey()) + ->addOperation( + PaymentOp::newNativePayment($destinationAccountId, 1) + ) +; + +// Sign and submit the transaction +$response = $transaction->submit($sourceKeypair->getSecret()); + +print "Response:" . PHP_EOL; +print_r($response->getRawData()); + +print PHP_EOL; print 'Payment succeeded!' . PHP_EOL; \ No newline at end of file diff --git a/getting-started/05-stream-payments.php b/getting-started/05-stream-payments.php index b0c69e1..698cf80 100755 --- a/getting-started/05-stream-payments.php +++ b/getting-started/05-stream-payments.php @@ -1,21 +1,21 @@ -getAccount('GA2C5RFPE6GCKMY3US5PAB6UZLKIGSPIUKSLRB6Q723BM2OARMDUYEJ5'); - - -print "Waiting for new payments to " . $account->getId() . PHP_EOL; - -$account->streamPayments('now', function(Payment $payment) { - printf('[%s] Amount: %s From %s' . PHP_EOL, - $payment->getType(), - $payment->getAmount(), - $payment->getSourceAccountId() - ); +getAccount('GA2C5RFPE6GCKMY3US5PAB6UZLKIGSPIUKSLRB6Q723BM2OARMDUYEJ5'); + + +print "Waiting for new payments to " . $account->getId() . PHP_EOL; + +$account->streamPayments('now', function(Payment $payment) { + printf('[%s] Amount: %s From %s' . PHP_EOL, + $payment->getType(), + $payment->getAmount(), + $payment->getSourceAccountId() + ); }); \ No newline at end of file diff --git a/getting-started/06-list-payments.php b/getting-started/06-list-payments.php index 3c1e44b..131b743 100755 --- a/getting-started/06-list-payments.php +++ b/getting-started/06-list-payments.php @@ -1,34 +1,34 @@ -getAccount('GA2C5RFPE6GCKMY3US5PAB6UZLKIGSPIUKSLRB6Q723BM2OARMDUYEJ5'); - -$currentCursor = null; -while (true) { - $resultsPerPage = 10; - $payments = $account->getPayments(null, $resultsPerPage); - - $seenResults = 0; - foreach ($payments as $payment) { - /** @var $payment \ZuluCrypto\StellarSdk\Model\Operation|\ZuluCrypto\StellarSdk\Model\AssetTransferInterface */ - // If the same cursor shows up twice, we're repeating results and should exit - if ($payment->getPagingToken() == $currentCursor) break 2; - - printf('[%s] Amount: %s From %s in Tx %s' . PHP_EOL, - $payment->getAssetTransferType(), - $payment->getAssetAmount(), - $payment->getFromAccountId(), - $payment->getTransactionHash() - ); - - $currentCursor = $payment->getPagingToken(); - } - - // Immediate exit if there aren't enough results to fill the page - if ($seenResults < $resultsPerPage) break; +getAccount('GA2C5RFPE6GCKMY3US5PAB6UZLKIGSPIUKSLRB6Q723BM2OARMDUYEJ5'); + +$currentCursor = null; +while (true) { + $resultsPerPage = 10; + $payments = $account->getPayments(null, $resultsPerPage); + + $seenResults = 0; + foreach ($payments as $payment) { + /** @var $payment \ZuluCrypto\StellarSdk\Model\Operation|\ZuluCrypto\StellarSdk\Model\AssetTransferInterface */ + // If the same cursor shows up twice, we're repeating results and should exit + if ($payment->getPagingToken() == $currentCursor) break 2; + + printf('[%s] Amount: %s From %s in Tx %s' . PHP_EOL, + $payment->getAssetTransferType(), + $payment->getAssetAmount(), + $payment->getFromAccountId(), + $payment->getTransactionHash() + ); + + $currentCursor = $payment->getPagingToken(); + } + + // Immediate exit if there aren't enough results to fill the page + if ($seenResults < $resultsPerPage) break; } \ No newline at end of file diff --git a/src/AddressableKey.php b/src/AddressableKey.php index 0fe73bb..6b0ef1a 100755 --- a/src/AddressableKey.php +++ b/src/AddressableKey.php @@ -1,125 +1,125 @@ -words = $this->loadWordlist($wordlistPath); - } - - /** - * Converts a mnemonic to raw bytes - * - * NOTE: this is NOT the raw bytes used for a Stellar key! See mnemonicToSeedBytes - * - * @param $mnenomic - * @return bool|string - */ - public function mnemonicToEntropy($mnenomic) - { - $bitstring = $this->parseMnemonic($mnenomic); - - // Calculate expected lengths - $numChecksumBits = strlen($bitstring) / 33; - $numEntropyBits = strlen($bitstring) - $numChecksumBits; - - // Get checksum bits from the end of the string - $checksumBits = substr($bitstring, -1 * $numChecksumBits); - $checksumHex = static::bitstringToHex($checksumBits); - - // Remaining bits are the entropy - $entropyBits = substr($bitstring, 0, $numEntropyBits); - $entropyHex = static::bitstringToHex($entropyBits); - - $entropyBytes = hex2bin($entropyHex); - - if ($checksumHex !== static::getEntropyChecksumHex($entropyBytes)) { - throw new \InvalidArgumentException('Invalid checksum'); - } - - return $entropyBytes; - } - - /** - * Converts a mnemonic and optional passphrase to a 64-byte string for use - * as entropy. - * - * Note that this is specific to the wordlist being used and is NOT portable - * across wordlists. - * - * In most cases, mnemonicToSeedBytesWithErrorChecking should be used since - * it will fail if there's a checksum error in the mnemonic - * - * @param $mnemonic - * @param string $passphrase - * @return string - */ - public function mnemonicToSeedBytes($mnemonic, $passphrase = '') - { - $salt = 'mnemonic' . $passphrase; - return hash_pbkdf2("sha512", $mnemonic, $salt, 2048, 64, true); - } - - /** - * Converts $mnemonic to seed bytes suitable for creating a new HDNode - * - * If the mnemonic is invalid, an exception is thrown - * - * @param $mnemonic - * @param string $passphrase - * @return string raw bytes - */ - public function mnemonicToSeedBytesWithErrorChecking($mnemonic, $passphrase = '') - { - // This will throw an exception if the embedded checksum is incorrect - $this->mnemonicToEntropy($mnemonic); - - return $this->mnemonicToSeedBytes($mnemonic, $passphrase); - } - - /** - * Parses a string of words and returns a string representing the binary - * encoding of the mnemonic (including checksum) - * - * Note that this is a literal string of "101101110" and not raw bytes! - * - * @param $mnemonic - * @return string - */ - protected function parseMnemonic($mnemonic) - { - $words = explode(' ', $mnemonic); - if (count($words) %3 !== 0) throw new \InvalidArgumentException('Invalid mnemonic (number of words must be a multiple of 3)'); - - $wordBitstrings = []; - foreach ($words as $word) { - $wordIdx = $this->getWordIndex($word); - - // Convert $wordIdx to an 11-bit number (preserving 0s) - $wordBitstrings[] = str_pad(decbin($wordIdx), 11, '0', STR_PAD_LEFT); - } - - // Return a string representing each bit - return join('', $wordBitstrings); - } - - /** - * @param $word - * @return int - * @throws \InvalidArgumentException - */ - protected function getWordIndex($word) - { - $index = 0; - - foreach ($this->words as $wordInList) { - if ($wordInList === $word) return $index; - - $index++; - } - - throw new \InvalidArgumentException(sprintf('Word "%s" not found in wordlist', $word)); - } - - /** - * @param $wordlistPath - * @return array - */ - protected function loadWordlist($wordlistPath) - { - $this->words = []; - if (!file_exists($wordlistPath)) throw new \InvalidArgumentException('Cannot load wordlist from "%s"', $wordlistPath); - - foreach (file($wordlistPath) as $word) { - $this->words[] = trim($word); - } - - return $this->words; - } +words = $this->loadWordlist($wordlistPath); + } + + /** + * Converts a mnemonic to raw bytes + * + * NOTE: this is NOT the raw bytes used for a Stellar key! See mnemonicToSeedBytes + * + * @param $mnenomic + * @return bool|string + */ + public function mnemonicToEntropy($mnenomic) + { + $bitstring = $this->parseMnemonic($mnenomic); + + // Calculate expected lengths + $numChecksumBits = strlen($bitstring) / 33; + $numEntropyBits = strlen($bitstring) - $numChecksumBits; + + // Get checksum bits from the end of the string + $checksumBits = substr($bitstring, -1 * $numChecksumBits); + $checksumHex = static::bitstringToHex($checksumBits); + + // Remaining bits are the entropy + $entropyBits = substr($bitstring, 0, $numEntropyBits); + $entropyHex = static::bitstringToHex($entropyBits); + + $entropyBytes = hex2bin($entropyHex); + + if ($checksumHex !== static::getEntropyChecksumHex($entropyBytes)) { + throw new \InvalidArgumentException('Invalid checksum'); + } + + return $entropyBytes; + } + + /** + * Converts a mnemonic and optional passphrase to a 64-byte string for use + * as entropy. + * + * Note that this is specific to the wordlist being used and is NOT portable + * across wordlists. + * + * In most cases, mnemonicToSeedBytesWithErrorChecking should be used since + * it will fail if there's a checksum error in the mnemonic + * + * @param $mnemonic + * @param string $passphrase + * @return string + */ + public function mnemonicToSeedBytes($mnemonic, $passphrase = '') + { + $salt = 'mnemonic' . $passphrase; + return hash_pbkdf2("sha512", $mnemonic, $salt, 2048, 64, true); + } + + /** + * Converts $mnemonic to seed bytes suitable for creating a new HDNode + * + * If the mnemonic is invalid, an exception is thrown + * + * @param $mnemonic + * @param string $passphrase + * @return string raw bytes + */ + public function mnemonicToSeedBytesWithErrorChecking($mnemonic, $passphrase = '') + { + // This will throw an exception if the embedded checksum is incorrect + $this->mnemonicToEntropy($mnemonic); + + return $this->mnemonicToSeedBytes($mnemonic, $passphrase); + } + + /** + * Parses a string of words and returns a string representing the binary + * encoding of the mnemonic (including checksum) + * + * Note that this is a literal string of "101101110" and not raw bytes! + * + * @param $mnemonic + * @return string + */ + protected function parseMnemonic($mnemonic) + { + $words = explode(' ', $mnemonic); + if (count($words) %3 !== 0) throw new \InvalidArgumentException('Invalid mnemonic (number of words must be a multiple of 3)'); + + $wordBitstrings = []; + foreach ($words as $word) { + $wordIdx = $this->getWordIndex($word); + + // Convert $wordIdx to an 11-bit number (preserving 0s) + $wordBitstrings[] = str_pad(decbin($wordIdx), 11, '0', STR_PAD_LEFT); + } + + // Return a string representing each bit + return join('', $wordBitstrings); + } + + /** + * @param $word + * @return int + * @throws \InvalidArgumentException + */ + protected function getWordIndex($word) + { + $index = 0; + + foreach ($this->words as $wordInList) { + if ($wordInList === $word) return $index; + + $index++; + } + + throw new \InvalidArgumentException(sprintf('Word "%s" not found in wordlist', $word)); + } + + /** + * @param $wordlistPath + * @return array + */ + protected function loadWordlist($wordlistPath) + { + $this->words = []; + if (!file_exists($wordlistPath)) throw new \InvalidArgumentException('Cannot load wordlist from "%s"', $wordlistPath); + + foreach (file($wordlistPath) as $word) { + $this->words[] = trim($word); + } + + return $this->words; + } } \ No newline at end of file diff --git a/src/Derivation/Bip39/wordlists/en.txt b/src/Derivation/Bip39/wordlists/en.txt index 942040e..9c7ab8a 100644 --- a/src/Derivation/Bip39/wordlists/en.txt +++ b/src/Derivation/Bip39/wordlists/en.txt @@ -1,2048 +1,2048 @@ -abandon -ability -able -about -above -absent -absorb -abstract -absurd -abuse -access -accident -account -accuse -achieve -acid -acoustic -acquire -across -act -action -actor -actress -actual -adapt -add -addict -address -adjust -admit -adult -advance -advice -aerobic -affair -afford -afraid -again -age -agent -agree -ahead -aim -air -airport -aisle -alarm -album -alcohol -alert -alien -all -alley -allow -almost -alone -alpha -already -also -alter -always -amateur -amazing -among -amount -amused -analyst -anchor -ancient -anger -angle -angry -animal -ankle -announce -annual -another -answer -antenna -antique -anxiety -any -apart -apology -appear -apple -approve -april -arch -arctic -area -arena -argue -arm -armed -armor -army -around -arrange -arrest -arrive -arrow -art -artefact -artist -artwork -ask -aspect -assault -asset -assist -assume -asthma -athlete -atom -attack -attend -attitude -attract -auction -audit -august -aunt -author -auto -autumn -average -avocado -avoid -awake -aware -away -awesome -awful -awkward -axis -baby -bachelor -bacon -badge -bag -balance -balcony -ball -bamboo -banana -banner -bar -barely -bargain -barrel -base -basic -basket -battle -beach -bean -beauty -because -become -beef -before -begin -behave -behind -believe -below -belt -bench -benefit -best -betray -better -between -beyond -bicycle -bid -bike -bind -biology -bird -birth -bitter -black -blade -blame -blanket -blast -bleak -bless -blind -blood -blossom -blouse -blue -blur -blush -board -boat -body -boil -bomb -bone -bonus -book -boost -border -boring -borrow -boss -bottom -bounce -box -boy -bracket -brain -brand -brass -brave -bread -breeze -brick -bridge -brief -bright -bring -brisk -broccoli -broken -bronze -broom -brother -brown -brush -bubble -buddy -budget -buffalo -build -bulb -bulk -bullet -bundle -bunker -burden -burger -burst -bus -business -busy -butter -buyer -buzz -cabbage -cabin -cable -cactus -cage -cake -call -calm -camera -camp -can -canal -cancel -candy -cannon -canoe -canvas -canyon -capable -capital -captain -car -carbon -card -cargo -carpet -carry -cart -case -cash -casino -castle -casual -cat -catalog -catch -category -cattle -caught -cause -caution -cave -ceiling -celery -cement -census -century -cereal -certain -chair -chalk -champion -change -chaos -chapter -charge -chase -chat -cheap -check -cheese -chef -cherry -chest -chicken -chief -child -chimney -choice -choose -chronic -chuckle -chunk -churn -cigar -cinnamon -circle -citizen -city -civil -claim -clap -clarify -claw -clay -clean -clerk -clever -click -client -cliff -climb -clinic -clip -clock -clog -close -cloth -cloud -clown -club -clump -cluster -clutch -coach -coast -coconut -code -coffee -coil -coin -collect -color -column -combine -come -comfort -comic -common -company -concert -conduct -confirm -congress -connect -consider -control -convince -cook -cool -copper -copy -coral -core -corn -correct -cost -cotton -couch -country -couple -course -cousin -cover -coyote -crack -cradle -craft -cram -crane -crash -crater -crawl -crazy -cream -credit -creek -crew -cricket -crime -crisp -critic -crop -cross -crouch -crowd -crucial -cruel -cruise -crumble -crunch -crush -cry -crystal -cube -culture -cup -cupboard -curious -current -curtain -curve -cushion -custom -cute -cycle -dad -damage -damp -dance -danger -daring -dash -daughter -dawn -day -deal -debate -debris -decade -december -decide -decline -decorate -decrease -deer -defense -define -defy -degree -delay -deliver -demand -demise -denial -dentist -deny -depart -depend -deposit -depth -deputy -derive -describe -desert -design -desk -despair -destroy -detail -detect -develop -device -devote -diagram -dial -diamond -diary -dice -diesel -diet -differ -digital -dignity -dilemma -dinner -dinosaur -direct -dirt -disagree -discover -disease -dish -dismiss -disorder -display -distance -divert -divide -divorce -dizzy -doctor -document -dog -doll -dolphin -domain -donate -donkey -donor -door -dose -double -dove -draft -dragon -drama -drastic -draw -dream -dress -drift -drill -drink -drip -drive -drop -drum -dry -duck -dumb -dune -during -dust -dutch -duty -dwarf -dynamic -eager -eagle -early -earn -earth -easily -east -easy -echo -ecology -economy -edge -edit -educate -effort -egg -eight -either -elbow -elder -electric -elegant -element -elephant -elevator -elite -else -embark -embody -embrace -emerge -emotion -employ -empower -empty -enable -enact -end -endless -endorse -enemy -energy -enforce -engage -engine -enhance -enjoy -enlist -enough -enrich -enroll -ensure -enter -entire -entry -envelope -episode -equal -equip -era -erase -erode -erosion -error -erupt -escape -essay -essence -estate -eternal -ethics -evidence -evil -evoke -evolve -exact -example -excess -exchange -excite -exclude -excuse -execute -exercise -exhaust -exhibit -exile -exist -exit -exotic -expand -expect -expire -explain -expose -express -extend -extra -eye -eyebrow -fabric -face -faculty -fade -faint -faith -fall -false -fame -family -famous -fan -fancy -fantasy -farm -fashion -fat -fatal -father -fatigue -fault -favorite -feature -february -federal -fee -feed -feel -female -fence -festival -fetch -fever -few -fiber -fiction -field -figure -file -film -filter -final -find -fine -finger -finish -fire -firm -first -fiscal -fish -fit -fitness -fix -flag -flame -flash -flat -flavor -flee -flight -flip -float -flock -floor -flower -fluid -flush -fly -foam -focus -fog -foil -fold -follow -food -foot -force -forest -forget -fork -fortune -forum -forward -fossil -foster -found -fox -fragile -frame -frequent -fresh -friend -fringe -frog -front -frost -frown -frozen -fruit -fuel -fun -funny -furnace -fury -future -gadget -gain -galaxy -gallery -game -gap -garage -garbage -garden -garlic -garment -gas -gasp -gate -gather -gauge -gaze -general -genius -genre -gentle -genuine -gesture -ghost -giant -gift -giggle -ginger -giraffe -girl -give -glad -glance -glare -glass -glide -glimpse -globe -gloom -glory -glove -glow -glue -goat -goddess -gold -good -goose -gorilla -gospel -gossip -govern -gown -grab -grace -grain -grant -grape -grass -gravity -great -green -grid -grief -grit -grocery -group -grow -grunt -guard -guess -guide -guilt -guitar -gun -gym -habit -hair -half -hammer -hamster -hand -happy -harbor -hard -harsh -harvest -hat -have -hawk -hazard -head -health -heart -heavy -hedgehog -height -hello -helmet -help -hen -hero -hidden -high -hill -hint -hip -hire -history -hobby -hockey -hold -hole -holiday -hollow -home -honey -hood -hope -horn -horror -horse -hospital -host -hotel -hour -hover -hub -huge -human -humble -humor -hundred -hungry -hunt -hurdle -hurry -hurt -husband -hybrid -ice -icon -idea -identify -idle -ignore -ill -illegal -illness -image -imitate -immense -immune -impact -impose -improve -impulse -inch -include -income -increase -index -indicate -indoor -industry -infant -inflict -inform -inhale -inherit -initial -inject -injury -inmate -inner -innocent -input -inquiry -insane -insect -inside -inspire -install -intact -interest -into -invest -invite -involve -iron -island -isolate -issue -item -ivory -jacket -jaguar -jar -jazz -jealous -jeans -jelly -jewel -job -join -joke -journey -joy -judge -juice -jump -jungle -junior -junk -just -kangaroo -keen -keep -ketchup -key -kick -kid -kidney -kind -kingdom -kiss -kit -kitchen -kite -kitten -kiwi -knee -knife -knock -know -lab -label -labor -ladder -lady -lake -lamp -language -laptop -large -later -latin -laugh -laundry -lava -law -lawn -lawsuit -layer -lazy -leader -leaf -learn -leave -lecture -left -leg -legal -legend -leisure -lemon -lend -length -lens -leopard -lesson -letter -level -liar -liberty -library -license -life -lift -light -like -limb -limit -link -lion -liquid -list -little -live -lizard -load -loan -lobster -local -lock -logic -lonely -long -loop -lottery -loud -lounge -love -loyal -lucky -luggage -lumber -lunar -lunch -luxury -lyrics -machine -mad -magic -magnet -maid -mail -main -major -make -mammal -man -manage -mandate -mango -mansion -manual -maple -marble -march -margin -marine -market -marriage -mask -mass -master -match -material -math -matrix -matter -maximum -maze -meadow -mean -measure -meat -mechanic -medal -media -melody -melt -member -memory -mention -menu -mercy -merge -merit -merry -mesh -message -metal -method -middle -midnight -milk -million -mimic -mind -minimum -minor -minute -miracle -mirror -misery -miss -mistake -mix -mixed -mixture -mobile -model -modify -mom -moment -monitor -monkey -monster -month -moon -moral -more -morning -mosquito -mother -motion -motor -mountain -mouse -move -movie -much -muffin -mule -multiply -muscle -museum -mushroom -music -must -mutual -myself -mystery -myth -naive -name -napkin -narrow -nasty -nation -nature -near -neck -need -negative -neglect -neither -nephew -nerve -nest -net -network -neutral -never -news -next -nice -night -noble -noise -nominee -noodle -normal -north -nose -notable -note -nothing -notice -novel -now -nuclear -number -nurse -nut -oak -obey -object -oblige -obscure -observe -obtain -obvious -occur -ocean -october -odor -off -offer -office -often -oil -okay -old -olive -olympic -omit -once -one -onion -online -only -open -opera -opinion -oppose -option -orange -orbit -orchard -order -ordinary -organ -orient -original -orphan -ostrich -other -outdoor -outer -output -outside -oval -oven -over -own -owner -oxygen -oyster -ozone -pact -paddle -page -pair -palace -palm -panda -panel -panic -panther -paper -parade -parent -park -parrot -party -pass -patch -path -patient -patrol -pattern -pause -pave -payment -peace -peanut -pear -peasant -pelican -pen -penalty -pencil -people -pepper -perfect -permit -person -pet -phone -photo -phrase -physical -piano -picnic -picture -piece -pig -pigeon -pill -pilot -pink -pioneer -pipe -pistol -pitch -pizza -place -planet -plastic -plate -play -please -pledge -pluck -plug -plunge -poem -poet -point -polar -pole -police -pond -pony -pool -popular -portion -position -possible -post -potato -pottery -poverty -powder -power -practice -praise -predict -prefer -prepare -present -pretty -prevent -price -pride -primary -print -priority -prison -private -prize -problem -process -produce -profit -program -project -promote -proof -property -prosper -protect -proud -provide -public -pudding -pull -pulp -pulse -pumpkin -punch -pupil -puppy -purchase -purity -purpose -purse -push -put -puzzle -pyramid -quality -quantum -quarter -question -quick -quit -quiz -quote -rabbit -raccoon -race -rack -radar -radio -rail -rain -raise -rally -ramp -ranch -random -range -rapid -rare -rate -rather -raven -raw -razor -ready -real -reason -rebel -rebuild -recall -receive -recipe -record -recycle -reduce -reflect -reform -refuse -region -regret -regular -reject -relax -release -relief -rely -remain -remember -remind -remove -render -renew -rent -reopen -repair -repeat -replace -report -require -rescue -resemble -resist -resource -response -result -retire -retreat -return -reunion -reveal -review -reward -rhythm -rib -ribbon -rice -rich -ride -ridge -rifle -right -rigid -ring -riot -ripple -risk -ritual -rival -river -road -roast -robot -robust -rocket -romance -roof -rookie -room -rose -rotate -rough -round -route -royal -rubber -rude -rug -rule -run -runway -rural -sad -saddle -sadness -safe -sail -salad -salmon -salon -salt -salute -same -sample -sand -satisfy -satoshi -sauce -sausage -save -say -scale -scan -scare -scatter -scene -scheme -school -science -scissors -scorpion -scout -scrap -screen -script -scrub -sea -search -season -seat -second -secret -section -security -seed -seek -segment -select -sell -seminar -senior -sense -sentence -series -service -session -settle -setup -seven -shadow -shaft -shallow -share -shed -shell -sheriff -shield -shift -shine -ship -shiver -shock -shoe -shoot -shop -short -shoulder -shove -shrimp -shrug -shuffle -shy -sibling -sick -side -siege -sight -sign -silent -silk -silly -silver -similar -simple -since -sing -siren -sister -situate -six -size -skate -sketch -ski -skill -skin -skirt -skull -slab -slam -sleep -slender -slice -slide -slight -slim -slogan -slot -slow -slush -small -smart -smile -smoke -smooth -snack -snake -snap -sniff -snow -soap -soccer -social -sock -soda -soft -solar -soldier -solid -solution -solve -someone -song -soon -sorry -sort -soul -sound -soup -source -south -space -spare -spatial -spawn -speak -special -speed -spell -spend -sphere -spice -spider -spike -spin -spirit -split -spoil -sponsor -spoon -sport -spot -spray -spread -spring -spy -square -squeeze -squirrel -stable -stadium -staff -stage -stairs -stamp -stand -start -state -stay -steak -steel -stem -step -stereo -stick -still -sting -stock -stomach -stone -stool -story -stove -strategy -street -strike -strong -struggle -student -stuff -stumble -style -subject -submit -subway -success -such -sudden -suffer -sugar -suggest -suit -summer -sun -sunny -sunset -super -supply -supreme -sure -surface -surge -surprise -surround -survey -suspect -sustain -swallow -swamp -swap -swarm -swear -sweet -swift -swim -swing -switch -sword -symbol -symptom -syrup -system -table -tackle -tag -tail -talent -talk -tank -tape -target -task -taste -tattoo -taxi -teach -team -tell -ten -tenant -tennis -tent -term -test -text -thank -that -theme -then -theory -there -they -thing -this -thought -three -thrive -throw -thumb -thunder -ticket -tide -tiger -tilt -timber -time -tiny -tip -tired -tissue -title -toast -tobacco -today -toddler -toe -together -toilet -token -tomato -tomorrow -tone -tongue -tonight -tool -tooth -top -topic -topple -torch -tornado -tortoise -toss -total -tourist -toward -tower -town -toy -track -trade -traffic -tragic -train -transfer -trap -trash -travel -tray -treat -tree -trend -trial -tribe -trick -trigger -trim -trip -trophy -trouble -truck -true -truly -trumpet -trust -truth -try -tube -tuition -tumble -tuna -tunnel -turkey -turn -turtle -twelve -twenty -twice -twin -twist -two -type -typical -ugly -umbrella -unable -unaware -uncle -uncover -under -undo -unfair -unfold -unhappy -uniform -unique -unit -universe -unknown -unlock -until -unusual -unveil -update -upgrade -uphold -upon -upper -upset -urban -urge -usage -use -used -useful -useless -usual -utility -vacant -vacuum -vague -valid -valley -valve -van -vanish -vapor -various -vast -vault -vehicle -velvet -vendor -venture -venue -verb -verify -version -very -vessel -veteran -viable -vibrant -vicious -victory -video -view -village -vintage -violin -virtual -virus -visa -visit -visual -vital -vivid -vocal -voice -void -volcano -volume -vote -voyage -wage -wagon -wait -walk -wall -walnut -want -warfare -warm -warrior -wash -wasp -waste -water -wave -way -wealth -weapon -wear -weasel -weather -web -wedding -weekend -weird -welcome -west -wet -whale -what -wheat -wheel -when -where -whip -whisper -wide -width -wife -wild -will -win -window -wine -wing -wink -winner -winter -wire -wisdom -wise -wish -witness -wolf -woman -wonder -wood -wool -word -work -world -worry -worth -wrap -wreck -wrestle -wrist -write -wrong -yard -year -yellow -you -young -youth -zebra -zero -zone -zoo +abandon +ability +able +about +above +absent +absorb +abstract +absurd +abuse +access +accident +account +accuse +achieve +acid +acoustic +acquire +across +act +action +actor +actress +actual +adapt +add +addict +address +adjust +admit +adult +advance +advice +aerobic +affair +afford +afraid +again +age +agent +agree +ahead +aim +air +airport +aisle +alarm +album +alcohol +alert +alien +all +alley +allow +almost +alone +alpha +already +also +alter +always +amateur +amazing +among +amount +amused +analyst +anchor +ancient +anger +angle +angry +animal +ankle +announce +annual +another +answer +antenna +antique +anxiety +any +apart +apology +appear +apple +approve +april +arch +arctic +area +arena +argue +arm +armed +armor +army +around +arrange +arrest +arrive +arrow +art +artefact +artist +artwork +ask +aspect +assault +asset +assist +assume +asthma +athlete +atom +attack +attend +attitude +attract +auction +audit +august +aunt +author +auto +autumn +average +avocado +avoid +awake +aware +away +awesome +awful +awkward +axis +baby +bachelor +bacon +badge +bag +balance +balcony +ball +bamboo +banana +banner +bar +barely +bargain +barrel +base +basic +basket +battle +beach +bean +beauty +because +become +beef +before +begin +behave +behind +believe +below +belt +bench +benefit +best +betray +better +between +beyond +bicycle +bid +bike +bind +biology +bird +birth +bitter +black +blade +blame +blanket +blast +bleak +bless +blind +blood +blossom +blouse +blue +blur +blush +board +boat +body +boil +bomb +bone +bonus +book +boost +border +boring +borrow +boss +bottom +bounce +box +boy +bracket +brain +brand +brass +brave +bread +breeze +brick +bridge +brief +bright +bring +brisk +broccoli +broken +bronze +broom +brother +brown +brush +bubble +buddy +budget +buffalo +build +bulb +bulk +bullet +bundle +bunker +burden +burger +burst +bus +business +busy +butter +buyer +buzz +cabbage +cabin +cable +cactus +cage +cake +call +calm +camera +camp +can +canal +cancel +candy +cannon +canoe +canvas +canyon +capable +capital +captain +car +carbon +card +cargo +carpet +carry +cart +case +cash +casino +castle +casual +cat +catalog +catch +category +cattle +caught +cause +caution +cave +ceiling +celery +cement +census +century +cereal +certain +chair +chalk +champion +change +chaos +chapter +charge +chase +chat +cheap +check +cheese +chef +cherry +chest +chicken +chief +child +chimney +choice +choose +chronic +chuckle +chunk +churn +cigar +cinnamon +circle +citizen +city +civil +claim +clap +clarify +claw +clay +clean +clerk +clever +click +client +cliff +climb +clinic +clip +clock +clog +close +cloth +cloud +clown +club +clump +cluster +clutch +coach +coast +coconut +code +coffee +coil +coin +collect +color +column +combine +come +comfort +comic +common +company +concert +conduct +confirm +congress +connect +consider +control +convince +cook +cool +copper +copy +coral +core +corn +correct +cost +cotton +couch +country +couple +course +cousin +cover +coyote +crack +cradle +craft +cram +crane +crash +crater +crawl +crazy +cream +credit +creek +crew +cricket +crime +crisp +critic +crop +cross +crouch +crowd +crucial +cruel +cruise +crumble +crunch +crush +cry +crystal +cube +culture +cup +cupboard +curious +current +curtain +curve +cushion +custom +cute +cycle +dad +damage +damp +dance +danger +daring +dash +daughter +dawn +day +deal +debate +debris +decade +december +decide +decline +decorate +decrease +deer +defense +define +defy +degree +delay +deliver +demand +demise +denial +dentist +deny +depart +depend +deposit +depth +deputy +derive +describe +desert +design +desk +despair +destroy +detail +detect +develop +device +devote +diagram +dial +diamond +diary +dice +diesel +diet +differ +digital +dignity +dilemma +dinner +dinosaur +direct +dirt +disagree +discover +disease +dish +dismiss +disorder +display +distance +divert +divide +divorce +dizzy +doctor +document +dog +doll +dolphin +domain +donate +donkey +donor +door +dose +double +dove +draft +dragon +drama +drastic +draw +dream +dress +drift +drill +drink +drip +drive +drop +drum +dry +duck +dumb +dune +during +dust +dutch +duty +dwarf +dynamic +eager +eagle +early +earn +earth +easily +east +easy +echo +ecology +economy +edge +edit +educate +effort +egg +eight +either +elbow +elder +electric +elegant +element +elephant +elevator +elite +else +embark +embody +embrace +emerge +emotion +employ +empower +empty +enable +enact +end +endless +endorse +enemy +energy +enforce +engage +engine +enhance +enjoy +enlist +enough +enrich +enroll +ensure +enter +entire +entry +envelope +episode +equal +equip +era +erase +erode +erosion +error +erupt +escape +essay +essence +estate +eternal +ethics +evidence +evil +evoke +evolve +exact +example +excess +exchange +excite +exclude +excuse +execute +exercise +exhaust +exhibit +exile +exist +exit +exotic +expand +expect +expire +explain +expose +express +extend +extra +eye +eyebrow +fabric +face +faculty +fade +faint +faith +fall +false +fame +family +famous +fan +fancy +fantasy +farm +fashion +fat +fatal +father +fatigue +fault +favorite +feature +february +federal +fee +feed +feel +female +fence +festival +fetch +fever +few +fiber +fiction +field +figure +file +film +filter +final +find +fine +finger +finish +fire +firm +first +fiscal +fish +fit +fitness +fix +flag +flame +flash +flat +flavor +flee +flight +flip +float +flock +floor +flower +fluid +flush +fly +foam +focus +fog +foil +fold +follow +food +foot +force +forest +forget +fork +fortune +forum +forward +fossil +foster +found +fox +fragile +frame +frequent +fresh +friend +fringe +frog +front +frost +frown +frozen +fruit +fuel +fun +funny +furnace +fury +future +gadget +gain +galaxy +gallery +game +gap +garage +garbage +garden +garlic +garment +gas +gasp +gate +gather +gauge +gaze +general +genius +genre +gentle +genuine +gesture +ghost +giant +gift +giggle +ginger +giraffe +girl +give +glad +glance +glare +glass +glide +glimpse +globe +gloom +glory +glove +glow +glue +goat +goddess +gold +good +goose +gorilla +gospel +gossip +govern +gown +grab +grace +grain +grant +grape +grass +gravity +great +green +grid +grief +grit +grocery +group +grow +grunt +guard +guess +guide +guilt +guitar +gun +gym +habit +hair +half +hammer +hamster +hand +happy +harbor +hard +harsh +harvest +hat +have +hawk +hazard +head +health +heart +heavy +hedgehog +height +hello +helmet +help +hen +hero +hidden +high +hill +hint +hip +hire +history +hobby +hockey +hold +hole +holiday +hollow +home +honey +hood +hope +horn +horror +horse +hospital +host +hotel +hour +hover +hub +huge +human +humble +humor +hundred +hungry +hunt +hurdle +hurry +hurt +husband +hybrid +ice +icon +idea +identify +idle +ignore +ill +illegal +illness +image +imitate +immense +immune +impact +impose +improve +impulse +inch +include +income +increase +index +indicate +indoor +industry +infant +inflict +inform +inhale +inherit +initial +inject +injury +inmate +inner +innocent +input +inquiry +insane +insect +inside +inspire +install +intact +interest +into +invest +invite +involve +iron +island +isolate +issue +item +ivory +jacket +jaguar +jar +jazz +jealous +jeans +jelly +jewel +job +join +joke +journey +joy +judge +juice +jump +jungle +junior +junk +just +kangaroo +keen +keep +ketchup +key +kick +kid +kidney +kind +kingdom +kiss +kit +kitchen +kite +kitten +kiwi +knee +knife +knock +know +lab +label +labor +ladder +lady +lake +lamp +language +laptop +large +later +latin +laugh +laundry +lava +law +lawn +lawsuit +layer +lazy +leader +leaf +learn +leave +lecture +left +leg +legal +legend +leisure +lemon +lend +length +lens +leopard +lesson +letter +level +liar +liberty +library +license +life +lift +light +like +limb +limit +link +lion +liquid +list +little +live +lizard +load +loan +lobster +local +lock +logic +lonely +long +loop +lottery +loud +lounge +love +loyal +lucky +luggage +lumber +lunar +lunch +luxury +lyrics +machine +mad +magic +magnet +maid +mail +main +major +make +mammal +man +manage +mandate +mango +mansion +manual +maple +marble +march +margin +marine +market +marriage +mask +mass +master +match +material +math +matrix +matter +maximum +maze +meadow +mean +measure +meat +mechanic +medal +media +melody +melt +member +memory +mention +menu +mercy +merge +merit +merry +mesh +message +metal +method +middle +midnight +milk +million +mimic +mind +minimum +minor +minute +miracle +mirror +misery +miss +mistake +mix +mixed +mixture +mobile +model +modify +mom +moment +monitor +monkey +monster +month +moon +moral +more +morning +mosquito +mother +motion +motor +mountain +mouse +move +movie +much +muffin +mule +multiply +muscle +museum +mushroom +music +must +mutual +myself +mystery +myth +naive +name +napkin +narrow +nasty +nation +nature +near +neck +need +negative +neglect +neither +nephew +nerve +nest +net +network +neutral +never +news +next +nice +night +noble +noise +nominee +noodle +normal +north +nose +notable +note +nothing +notice +novel +now +nuclear +number +nurse +nut +oak +obey +object +oblige +obscure +observe +obtain +obvious +occur +ocean +october +odor +off +offer +office +often +oil +okay +old +olive +olympic +omit +once +one +onion +online +only +open +opera +opinion +oppose +option +orange +orbit +orchard +order +ordinary +organ +orient +original +orphan +ostrich +other +outdoor +outer +output +outside +oval +oven +over +own +owner +oxygen +oyster +ozone +pact +paddle +page +pair +palace +palm +panda +panel +panic +panther +paper +parade +parent +park +parrot +party +pass +patch +path +patient +patrol +pattern +pause +pave +payment +peace +peanut +pear +peasant +pelican +pen +penalty +pencil +people +pepper +perfect +permit +person +pet +phone +photo +phrase +physical +piano +picnic +picture +piece +pig +pigeon +pill +pilot +pink +pioneer +pipe +pistol +pitch +pizza +place +planet +plastic +plate +play +please +pledge +pluck +plug +plunge +poem +poet +point +polar +pole +police +pond +pony +pool +popular +portion +position +possible +post +potato +pottery +poverty +powder +power +practice +praise +predict +prefer +prepare +present +pretty +prevent +price +pride +primary +print +priority +prison +private +prize +problem +process +produce +profit +program +project +promote +proof +property +prosper +protect +proud +provide +public +pudding +pull +pulp +pulse +pumpkin +punch +pupil +puppy +purchase +purity +purpose +purse +push +put +puzzle +pyramid +quality +quantum +quarter +question +quick +quit +quiz +quote +rabbit +raccoon +race +rack +radar +radio +rail +rain +raise +rally +ramp +ranch +random +range +rapid +rare +rate +rather +raven +raw +razor +ready +real +reason +rebel +rebuild +recall +receive +recipe +record +recycle +reduce +reflect +reform +refuse +region +regret +regular +reject +relax +release +relief +rely +remain +remember +remind +remove +render +renew +rent +reopen +repair +repeat +replace +report +require +rescue +resemble +resist +resource +response +result +retire +retreat +return +reunion +reveal +review +reward +rhythm +rib +ribbon +rice +rich +ride +ridge +rifle +right +rigid +ring +riot +ripple +risk +ritual +rival +river +road +roast +robot +robust +rocket +romance +roof +rookie +room +rose +rotate +rough +round +route +royal +rubber +rude +rug +rule +run +runway +rural +sad +saddle +sadness +safe +sail +salad +salmon +salon +salt +salute +same +sample +sand +satisfy +satoshi +sauce +sausage +save +say +scale +scan +scare +scatter +scene +scheme +school +science +scissors +scorpion +scout +scrap +screen +script +scrub +sea +search +season +seat +second +secret +section +security +seed +seek +segment +select +sell +seminar +senior +sense +sentence +series +service +session +settle +setup +seven +shadow +shaft +shallow +share +shed +shell +sheriff +shield +shift +shine +ship +shiver +shock +shoe +shoot +shop +short +shoulder +shove +shrimp +shrug +shuffle +shy +sibling +sick +side +siege +sight +sign +silent +silk +silly +silver +similar +simple +since +sing +siren +sister +situate +six +size +skate +sketch +ski +skill +skin +skirt +skull +slab +slam +sleep +slender +slice +slide +slight +slim +slogan +slot +slow +slush +small +smart +smile +smoke +smooth +snack +snake +snap +sniff +snow +soap +soccer +social +sock +soda +soft +solar +soldier +solid +solution +solve +someone +song +soon +sorry +sort +soul +sound +soup +source +south +space +spare +spatial +spawn +speak +special +speed +spell +spend +sphere +spice +spider +spike +spin +spirit +split +spoil +sponsor +spoon +sport +spot +spray +spread +spring +spy +square +squeeze +squirrel +stable +stadium +staff +stage +stairs +stamp +stand +start +state +stay +steak +steel +stem +step +stereo +stick +still +sting +stock +stomach +stone +stool +story +stove +strategy +street +strike +strong +struggle +student +stuff +stumble +style +subject +submit +subway +success +such +sudden +suffer +sugar +suggest +suit +summer +sun +sunny +sunset +super +supply +supreme +sure +surface +surge +surprise +surround +survey +suspect +sustain +swallow +swamp +swap +swarm +swear +sweet +swift +swim +swing +switch +sword +symbol +symptom +syrup +system +table +tackle +tag +tail +talent +talk +tank +tape +target +task +taste +tattoo +taxi +teach +team +tell +ten +tenant +tennis +tent +term +test +text +thank +that +theme +then +theory +there +they +thing +this +thought +three +thrive +throw +thumb +thunder +ticket +tide +tiger +tilt +timber +time +tiny +tip +tired +tissue +title +toast +tobacco +today +toddler +toe +together +toilet +token +tomato +tomorrow +tone +tongue +tonight +tool +tooth +top +topic +topple +torch +tornado +tortoise +toss +total +tourist +toward +tower +town +toy +track +trade +traffic +tragic +train +transfer +trap +trash +travel +tray +treat +tree +trend +trial +tribe +trick +trigger +trim +trip +trophy +trouble +truck +true +truly +trumpet +trust +truth +try +tube +tuition +tumble +tuna +tunnel +turkey +turn +turtle +twelve +twenty +twice +twin +twist +two +type +typical +ugly +umbrella +unable +unaware +uncle +uncover +under +undo +unfair +unfold +unhappy +uniform +unique +unit +universe +unknown +unlock +until +unusual +unveil +update +upgrade +uphold +upon +upper +upset +urban +urge +usage +use +used +useful +useless +usual +utility +vacant +vacuum +vague +valid +valley +valve +van +vanish +vapor +various +vast +vault +vehicle +velvet +vendor +venture +venue +verb +verify +version +very +vessel +veteran +viable +vibrant +vicious +victory +video +view +village +vintage +violin +virtual +virus +visa +visit +visual +vital +vivid +vocal +voice +void +volcano +volume +vote +voyage +wage +wagon +wait +walk +wall +walnut +want +warfare +warm +warrior +wash +wasp +waste +water +wave +way +wealth +weapon +wear +weasel +weather +web +wedding +weekend +weird +welcome +west +wet +whale +what +wheat +wheel +when +where +whip +whisper +wide +width +wife +wild +will +win +window +wine +wing +wink +winner +winter +wire +wisdom +wise +wish +witness +wolf +woman +wonder +wood +wool +word +work +world +worry +worth +wrap +wreck +wrestle +wrist +write +wrong +yard +year +yellow +you +young +youth +zebra +zero +zone +zoo diff --git a/src/Derivation/HdNode.php b/src/Derivation/HdNode.php index de48962..4954bff 100644 --- a/src/Derivation/HdNode.php +++ b/src/Derivation/HdNode.php @@ -1,146 +1,146 @@ -privateKeyBytes = $privateKeyBytes; - $this->chainCodeBytes = $chainCodeBytes; - } - - /** - * @param $index int automatically converted to a hardened index - * @return HdNode - */ - public function derive($index) - { - $index = intval($index) + intval(static::HARDENED_MINIMUM_INDEX); - if ($index < static::HARDENED_MINIMUM_INDEX) throw new \InvalidArgumentException('Only hardened indexes are supported'); - - // big-endian unsigned long (4 bytes) - $indexBytes = pack('N', $index); - $key = pack('C', 0x00) . $this->privateKeyBytes . $indexBytes; - - $hmac = hash_hmac('sha512', $key, $this->chainCodeBytes, true); - - return new HdNode( - substr($hmac, 0, 32), - substr($hmac, 32, 32) - ); - } - - /** - * Derives a path like m/0'/1' - * @param $path - * @return HdNode - */ - public function derivePath($path) - { - $pathParts = $this->parseDerivationPath($path); - - $derived = $this; - foreach ($pathParts as $index) { - $derived = $derived->derive($index); - } - - return $derived; - } - - /** - * Takes a path like "m/0'/1'" and returns an array of indexes to derive - * - * Note that since this class assumes all indexes are hardened, the returned - * array for the above example would be: - * [0, 1] - * - * @param $path - * @return array - */ - protected function parseDerivationPath($path) - { - $parsed = []; - $parts = explode('/', $path); - if (strtolower($parts[0]) != 'm') throw new \InvalidArgumentException('Path must start with "m"'); - - // Remove initial 'm' since it refers to the current HdNode - array_shift($parts); - - // Add each part to the return value - foreach ($parts as $part) { - // Each subsequent node must be hardened - if (strpos($part, "'") != (strlen($part)-1)) throw new \InvalidArgumentException('Path can only contain hardened indexes'); - $part = str_replace("'", '', $part); - - if (!is_numeric($part)) throw new \InvalidArgumentException('Path must be numeric'); - - $parsed[] = intval($part); - } - - return $parsed; - } - - /** - * @return string - */ - public function getPrivateKeyBytes() - { - return $this->privateKeyBytes; - } - - /** - * @return string - */ - public function getChainCodeBytes() - { - return $this->chainCodeBytes; - } +privateKeyBytes = $privateKeyBytes; + $this->chainCodeBytes = $chainCodeBytes; + } + + /** + * @param $index int automatically converted to a hardened index + * @return HdNode + */ + public function derive($index) + { + $index = intval($index) + intval(static::HARDENED_MINIMUM_INDEX); + if ($index < static::HARDENED_MINIMUM_INDEX) throw new \InvalidArgumentException('Only hardened indexes are supported'); + + // big-endian unsigned long (4 bytes) + $indexBytes = pack('N', $index); + $key = pack('C', 0x00) . $this->privateKeyBytes . $indexBytes; + + $hmac = hash_hmac('sha512', $key, $this->chainCodeBytes, true); + + return new HdNode( + substr($hmac, 0, 32), + substr($hmac, 32, 32) + ); + } + + /** + * Derives a path like m/0'/1' + * @param $path + * @return HdNode + */ + public function derivePath($path) + { + $pathParts = $this->parseDerivationPath($path); + + $derived = $this; + foreach ($pathParts as $index) { + $derived = $derived->derive($index); + } + + return $derived; + } + + /** + * Takes a path like "m/0'/1'" and returns an array of indexes to derive + * + * Note that since this class assumes all indexes are hardened, the returned + * array for the above example would be: + * [0, 1] + * + * @param $path + * @return array + */ + protected function parseDerivationPath($path) + { + $parsed = []; + $parts = explode('/', $path); + if (strtolower($parts[0]) != 'm') throw new \InvalidArgumentException('Path must start with "m"'); + + // Remove initial 'm' since it refers to the current HdNode + array_shift($parts); + + // Add each part to the return value + foreach ($parts as $part) { + // Each subsequent node must be hardened + if (strpos($part, "'") != (strlen($part)-1)) throw new \InvalidArgumentException('Path can only contain hardened indexes'); + $part = str_replace("'", '', $part); + + if (!is_numeric($part)) throw new \InvalidArgumentException('Path must be numeric'); + + $parsed[] = intval($part); + } + + return $parsed; + } + + /** + * @return string + */ + public function getPrivateKeyBytes() + { + return $this->privateKeyBytes; + } + + /** + * @return string + */ + public function getChainCodeBytes() + { + return $this->chainCodeBytes; + } } \ No newline at end of file diff --git a/src/History/BucketLevel.php b/src/History/BucketLevel.php index d670e33..8fddaf6 100644 --- a/src/History/BucketLevel.php +++ b/src/History/BucketLevel.php @@ -1,86 +1,86 @@ -curr = $raw['curr']; - $object->snap = $raw['snap']; - $object->next = $raw['next']; - - return $object; - } - - public function __construct($level) - { - $this->level = $level; - } - - /** - * Returns an array of unique sha256 hashes in this bucket level - * - * @return array - */ - public function getUniqueBucketHashes() - { - $hashes = []; - - if ($this->curr != self::HASH_EMPTY) $hashes[] = $this->curr; - if ($this->snap != self::HASH_EMPTY) $hashes[] = $this->snap; - - return array_values(array_unique($hashes)); - } +curr = $raw['curr']; + $object->snap = $raw['snap']; + $object->next = $raw['next']; + + return $object; + } + + public function __construct($level) + { + $this->level = $level; + } + + /** + * Returns an array of unique sha256 hashes in this bucket level + * + * @return array + */ + public function getUniqueBucketHashes() + { + $hashes = []; + + if ($this->curr != self::HASH_EMPTY) $hashes[] = $this->curr; + if ($this->snap != self::HASH_EMPTY) $hashes[] = $this->snap; + + return array_values(array_unique($hashes)); + } } \ No newline at end of file diff --git a/src/History/BucketList.php b/src/History/BucketList.php index 353a289..119678f 100644 --- a/src/History/BucketList.php +++ b/src/History/BucketList.php @@ -1,53 +1,53 @@ -bucketLevels = []; - } - - /** - * @param $raw - * @param null $level defaults to the next unoccupied level - * @return null|BucketLevel - */ - public function addLevelFromRaw($raw, $level = null) - { - if ($level === null) { - $level = count($this->bucketLevels); - } - - $bucketLevel = BucketLevel::fromRaw($raw, $level); - - $this->bucketLevels[] = $bucketLevel; - - return $bucketLevel; - } - - /** - * @return array|string[] sha256 bucket hashes - */ - public function getUniqueBucketHashes() - { - $hashes = []; - - foreach ($this->bucketLevels as $bucketLevel) { - $hashes = array_merge($hashes, $bucketLevel->getUniqueBucketHashes()); - } - - return array_values(array_unique($hashes)); - } +bucketLevels = []; + } + + /** + * @param $raw + * @param null $level defaults to the next unoccupied level + * @return null|BucketLevel + */ + public function addLevelFromRaw($raw, $level = null) + { + if ($level === null) { + $level = count($this->bucketLevels); + } + + $bucketLevel = BucketLevel::fromRaw($raw, $level); + + $this->bucketLevels[] = $bucketLevel; + + return $bucketLevel; + } + + /** + * @return array|string[] sha256 bucket hashes + */ + public function getUniqueBucketHashes() + { + $hashes = []; + + foreach ($this->bucketLevels as $bucketLevel) { + $hashes = array_merge($hashes, $bucketLevel->getUniqueBucketHashes()); + } + + return array_values(array_unique($hashes)); + } } \ No newline at end of file diff --git a/src/History/HistoryArchiveState.php b/src/History/HistoryArchiveState.php index 4c4abc1..e8b4081 100644 --- a/src/History/HistoryArchiveState.php +++ b/src/History/HistoryArchiveState.php @@ -1,97 +1,97 @@ -version = $raw['version']; - $object->server = $raw['server']; - $object->currentLedger = $raw['currentLedger']; - - foreach ($raw['currentBuckets'] as $rawBucketLevel) { - $object->addBucketFromRaw($rawBucketLevel); - } - - return $object; - } - - /** - * @param $path - * @return HistoryArchiveState - */ - public static function fromFile($path) - { - try { - return static::fromRaw(Json::mustDecode(file_get_contents($path))); - } catch (\InvalidArgumentException $e) { - throw new \ErrorException(sprintf('Error decoding json in %s: %s', $path, $e->getMessage())); - } - } - - public function __construct() - { - $this->currentBuckets = new BucketList(); - } - - /** - * @param $raw - * @param null $level - * @return null|BucketLevel - */ - public function addBucketFromRaw($raw, $level = null) - { - return $this->currentBuckets->addLevelFromRaw($raw, $level); - } - - /** - * @return array|string[] sha256 hashes - */ - public function getUniqueBucketHashes() - { - return $this->currentBuckets->getUniqueBucketHashes(); - } +version = $raw['version']; + $object->server = $raw['server']; + $object->currentLedger = $raw['currentLedger']; + + foreach ($raw['currentBuckets'] as $rawBucketLevel) { + $object->addBucketFromRaw($rawBucketLevel); + } + + return $object; + } + + /** + * @param $path + * @return HistoryArchiveState + */ + public static function fromFile($path) + { + try { + return static::fromRaw(Json::mustDecode(file_get_contents($path))); + } catch (\InvalidArgumentException $e) { + throw new \ErrorException(sprintf('Error decoding json in %s: %s', $path, $e->getMessage())); + } + } + + public function __construct() + { + $this->currentBuckets = new BucketList(); + } + + /** + * @param $raw + * @param null $level + * @return null|BucketLevel + */ + public function addBucketFromRaw($raw, $level = null) + { + return $this->currentBuckets->addLevelFromRaw($raw, $level); + } + + /** + * @return array|string[] sha256 hashes + */ + public function getUniqueBucketHashes() + { + return $this->currentBuckets->getUniqueBucketHashes(); + } } \ No newline at end of file diff --git a/src/History/HttpHistoryArchive.php b/src/History/HttpHistoryArchive.php index 4b8c752..7a552c4 100644 --- a/src/History/HttpHistoryArchive.php +++ b/src/History/HttpHistoryArchive.php @@ -1,182 +1,182 @@ -rootUrl = $rootUrl; - $this->storageRoot = $storageRoot; - - $this->httpClient = new Client([ - 'base_uri' => $rootUrl, - ]); - } - - public function downloadAll() - { - $this->syncRootHas(); - - $startingLedger = 64-1; - $ledgerIncrement = 64; - $currLedger = $startingLedger; - $percentComplete = 0; - while ($currLedger < $this->rootHas['currentLedger']) { - $ledgerHex = sprintf("%x", $currLedger); - $ledgerHex = str_pad($ledgerHex, 8, '0', STR_PAD_LEFT); - - // Get HAS file - $hasPath = $this->getHashedLedgerSubdirectory('history.json', $ledgerHex); - $localHasPath = $this->syncFile($hasPath); - - $archiveState = HistoryArchiveState::fromFile($localHasPath); - - // Bucket files - foreach ($archiveState->getUniqueBucketHashes() as $bucketHash) { - $bucketPath = $this->getHashedBucketSubdirectory($bucketHash); - $this->syncFile($bucketPath); - } - - // Other files - $this->syncFile($this->getHashedLedgerSubdirectory('ledger.xdr.gz', $ledgerHex)); - $this->syncFile($this->getHashedLedgerSubdirectory('transactions.xdr.gz', $ledgerHex)); - $this->syncFile($this->getHashedLedgerSubdirectory('results.xdr.gz', $ledgerHex)); - $this->syncFile($this->getHashedLedgerSubdirectory('scp.xdr.gz', $ledgerHex), false, true); - - $currLedger += $ledgerIncrement; - $percentComplete = round(($currLedger / $this->rootHas['currentLedger']) * 100); - } - } - - public function syncRootHas() - { - $response = $this->httpClient->get('.well-known/stellar-history.json'); - - $this->rootHas = Json::mustDecode($response->getBody()); - } - - /** - * Downloads $relativeUrl to the corresponding location on the local filesystem - * - * @param $relativeUrl - * @param bool $forceDownload force download even if the file is present locally - * @param bool $allowMissing allow 404 responses - * @return string - * @throws \ErrorException - */ - public function syncFile($relativeUrl, $forceDownload = false, $allowMissing = false) - { - $fs = new Filesystem(); - - // Target file to save to will match the relativeUrl being requested, but - // with the correct directory separator - $targetFile = str_replace('/', DIRECTORY_SEPARATOR, $relativeUrl); - $targetFile = $this->storageRoot . $targetFile; - - // Files won't change and are only written after a successful download, so - // if it exists there's no need to download it again - if (!$forceDownload && $fs->exists($targetFile)) return $targetFile; - - $tmpFile = $fs->tempnam(sys_get_temp_dir(), 'stellar-sync-tmp'); - $response = $this->httpClient->request('GET', $relativeUrl, [ - 'sink' => $tmpFile, - 'http_errors' => false, - ]); - - // Response succeeded - if ($response->getStatusCode() == 200) { - // 200 is always OK - } - // 404, but missing files are ok - elseif ($allowMissing && $response->getStatusCode() == 404) { - // this is OK - } - // Error response or 404 with $allowMissing false - else { - throw new \ErrorException(sprintf('HTTP %s: %s', $response->getStatusCode(), $response->getBody())); - } - - // Move temporary file into its final location - $fs->mkdir(dirname($targetFile), 0700); - $fs->rename($tmpFile, $targetFile); - - // Basic rate limiting - usleep(20000); - return $targetFile; - } - - protected function getHashedLedgerSubdirectory($filename, $prefixHex) - { - // Parse the filename (eg: ledger.xdr.gz) into category (ledger) and extension (.xdr.gz) - $parts = explode(".", $filename); - $category = array_shift($parts); - $extension = join('.', $parts); - $subdir = $category; - - // Three levels of subdirectories - $subdir .= '/' . substr($prefixHex, 0, 2); - $subdir .= '/' . substr($prefixHex, 2, 2); - $subdir .= '/' . substr($prefixHex, 4, 2); - - // Then the filename + hex + extension - return sprintf('%s/%s-%s.%s', - $subdir, - $category, $prefixHex, $extension - ); - } - - protected function getHashedBucketSubdirectory($prefixHex) - { - $subdir = 'bucket'; - - // Three levels of subdirectories - $subdir .= '/' . substr($prefixHex, 0, 2); - $subdir .= '/' . substr($prefixHex, 2, 2); - $subdir .= '/' . substr($prefixHex, 4, 2); - - return sprintf('%s/bucket-%s.xdr.gz', - $subdir, - $prefixHex - ); - } +rootUrl = $rootUrl; + $this->storageRoot = $storageRoot; + + $this->httpClient = new Client([ + 'base_uri' => $rootUrl, + ]); + } + + public function downloadAll() + { + $this->syncRootHas(); + + $startingLedger = 64-1; + $ledgerIncrement = 64; + $currLedger = $startingLedger; + $percentComplete = 0; + while ($currLedger < $this->rootHas['currentLedger']) { + $ledgerHex = sprintf("%x", $currLedger); + $ledgerHex = str_pad($ledgerHex, 8, '0', STR_PAD_LEFT); + + // Get HAS file + $hasPath = $this->getHashedLedgerSubdirectory('history.json', $ledgerHex); + $localHasPath = $this->syncFile($hasPath); + + $archiveState = HistoryArchiveState::fromFile($localHasPath); + + // Bucket files + foreach ($archiveState->getUniqueBucketHashes() as $bucketHash) { + $bucketPath = $this->getHashedBucketSubdirectory($bucketHash); + $this->syncFile($bucketPath); + } + + // Other files + $this->syncFile($this->getHashedLedgerSubdirectory('ledger.xdr.gz', $ledgerHex)); + $this->syncFile($this->getHashedLedgerSubdirectory('transactions.xdr.gz', $ledgerHex)); + $this->syncFile($this->getHashedLedgerSubdirectory('results.xdr.gz', $ledgerHex)); + $this->syncFile($this->getHashedLedgerSubdirectory('scp.xdr.gz', $ledgerHex), false, true); + + $currLedger += $ledgerIncrement; + $percentComplete = round(($currLedger / $this->rootHas['currentLedger']) * 100); + } + } + + public function syncRootHas() + { + $response = $this->httpClient->get('.well-known/stellar-history.json'); + + $this->rootHas = Json::mustDecode($response->getBody()); + } + + /** + * Downloads $relativeUrl to the corresponding location on the local filesystem + * + * @param $relativeUrl + * @param bool $forceDownload force download even if the file is present locally + * @param bool $allowMissing allow 404 responses + * @return string + * @throws \ErrorException + */ + public function syncFile($relativeUrl, $forceDownload = false, $allowMissing = false) + { + $fs = new Filesystem(); + + // Target file to save to will match the relativeUrl being requested, but + // with the correct directory separator + $targetFile = str_replace('/', DIRECTORY_SEPARATOR, $relativeUrl); + $targetFile = $this->storageRoot . $targetFile; + + // Files won't change and are only written after a successful download, so + // if it exists there's no need to download it again + if (!$forceDownload && $fs->exists($targetFile)) return $targetFile; + + $tmpFile = $fs->tempnam(sys_get_temp_dir(), 'stellar-sync-tmp'); + $response = $this->httpClient->request('GET', $relativeUrl, [ + 'sink' => $tmpFile, + 'http_errors' => false, + ]); + + // Response succeeded + if ($response->getStatusCode() == 200) { + // 200 is always OK + } + // 404, but missing files are ok + elseif ($allowMissing && $response->getStatusCode() == 404) { + // this is OK + } + // Error response or 404 with $allowMissing false + else { + throw new \ErrorException(sprintf('HTTP %s: %s', $response->getStatusCode(), $response->getBody())); + } + + // Move temporary file into its final location + $fs->mkdir(dirname($targetFile), 0700); + $fs->rename($tmpFile, $targetFile); + + // Basic rate limiting + usleep(20000); + return $targetFile; + } + + protected function getHashedLedgerSubdirectory($filename, $prefixHex) + { + // Parse the filename (eg: ledger.xdr.gz) into category (ledger) and extension (.xdr.gz) + $parts = explode(".", $filename); + $category = array_shift($parts); + $extension = join('.', $parts); + $subdir = $category; + + // Three levels of subdirectories + $subdir .= '/' . substr($prefixHex, 0, 2); + $subdir .= '/' . substr($prefixHex, 2, 2); + $subdir .= '/' . substr($prefixHex, 4, 2); + + // Then the filename + hex + extension + return sprintf('%s/%s-%s.%s', + $subdir, + $category, $prefixHex, $extension + ); + } + + protected function getHashedBucketSubdirectory($prefixHex) + { + $subdir = 'bucket'; + + // Three levels of subdirectories + $subdir .= '/' . substr($prefixHex, 0, 2); + $subdir .= '/' . substr($prefixHex, 2, 2); + $subdir .= '/' . substr($prefixHex, 4, 2); + + return sprintf('%s/bucket-%s.xdr.gz', + $subdir, + $prefixHex + ); + } } \ No newline at end of file diff --git a/src/Horizon/Api/HorizonResponse.php b/src/Horizon/Api/HorizonResponse.php index b38135f..f7e182d 100755 --- a/src/Horizon/Api/HorizonResponse.php +++ b/src/Horizon/Api/HorizonResponse.php @@ -1,74 +1,74 @@ -rawData = @json_decode($jsonEncodedData, true); - - if (null === $this->rawData && json_last_error() != JSON_ERROR_NONE) { - throw new \InvalidArgumentException(sprintf("Error in json_decode: %s", json_last_error_msg())); - } - } - - /** - * @return array - */ - public function getRawData() - { - return $this->rawData; - } - - /** - * Returns the value of $fieldName or null if $fieldName is not in the response - * - * @param $fieldName - * @return mixed|null - */ - public function getField($fieldName) - { - if (!isset($this->rawData[$fieldName])) return null; - - return $this->rawData[$fieldName]; - } - - /** - * Throws an exception if $fieldName is not present in the response - * - * @param $fieldName - * @throws \InvalidArgumentException - * @return mixed|null - */ - public function mustGetField($fieldName) - { - if (!isset($this->rawData[$fieldName])) throw new \InvalidArgumentException(sprintf("Field '%s' not present in response", $fieldName)); - - return $this->rawData[$fieldName]; - } - - public function getRecords($limit = 100) - { - // todo: support paging - - $records = []; - foreach ($this->rawData['_embedded']['records'] as $rawRecord) { - $record = $rawRecord; - unset($record['_links']); - - $records[] = $record; - } - - return $records; - } +rawData = @json_decode($jsonEncodedData, true); + + if (null === $this->rawData && json_last_error() != JSON_ERROR_NONE) { + throw new \InvalidArgumentException(sprintf("Error in json_decode: %s", json_last_error_msg())); + } + } + + /** + * @return array + */ + public function getRawData() + { + return $this->rawData; + } + + /** + * Returns the value of $fieldName or null if $fieldName is not in the response + * + * @param $fieldName + * @return mixed|null + */ + public function getField($fieldName) + { + if (!isset($this->rawData[$fieldName])) return null; + + return $this->rawData[$fieldName]; + } + + /** + * Throws an exception if $fieldName is not present in the response + * + * @param $fieldName + * @throws \InvalidArgumentException + * @return mixed|null + */ + public function mustGetField($fieldName) + { + if (!isset($this->rawData[$fieldName])) throw new \InvalidArgumentException(sprintf("Field '%s' not present in response", $fieldName)); + + return $this->rawData[$fieldName]; + } + + public function getRecords($limit = 100) + { + // todo: support paging + + $records = []; + foreach ($this->rawData['_embedded']['records'] as $rawRecord) { + $record = $rawRecord; + unset($record['_links']); + + $records[] = $record; + } + + return $records; + } } \ No newline at end of file diff --git a/src/Horizon/Api/PostTransactionResponse.php b/src/Horizon/Api/PostTransactionResponse.php index c23abc7..ba00d87 100644 --- a/src/Horizon/Api/PostTransactionResponse.php +++ b/src/Horizon/Api/PostTransactionResponse.php @@ -1,64 +1,64 @@ -rawData)); - } - - public function __construct($jsonEncodedData) - { - parent::__construct($jsonEncodedData); - - $this->parseRawData($this->rawData); - } - - /** - * Parses the raw response data and populates this object - * - * @param $rawData - * @throws \ErrorException - */ - protected function parseRawData($rawData) - { - if (!$rawData) return; - - if (!empty($rawData['result_xdr'])) { - $xdr = new XdrBuffer(base64_decode($rawData['result_xdr'])); - $this->result = TransactionResult::fromXdr($xdr); - } - } - - /** - * @return TransactionResult - */ - public function getResult() - { - return $this->result; - } - - /** - * @param TransactionResult $result - */ - public function setResult($result) - { - $this->result = $result; - } +rawData)); + } + + public function __construct($jsonEncodedData) + { + parent::__construct($jsonEncodedData); + + $this->parseRawData($this->rawData); + } + + /** + * Parses the raw response data and populates this object + * + * @param $rawData + * @throws \ErrorException + */ + protected function parseRawData($rawData) + { + if (!$rawData) return; + + if (!empty($rawData['result_xdr'])) { + $xdr = new XdrBuffer(base64_decode($rawData['result_xdr'])); + $this->result = TransactionResult::fromXdr($xdr); + } + } + + /** + * @return TransactionResult + */ + public function getResult() + { + return $this->result; + } + + /** + * @param TransactionResult $result + */ + public function setResult($result) + { + $this->result = $result; + } } \ No newline at end of file diff --git a/src/Horizon/ApiClient.php b/src/Horizon/ApiClient.php index 60001e4..5f5bb43 100755 --- a/src/Horizon/ApiClient.php +++ b/src/Horizon/ApiClient.php @@ -1,490 +1,490 @@ -isTestnet = true; - - return $apiClient; - } - - /** - * @return ApiClient - */ - public static function newPublicClient() - { - return new ApiClient('https://horizon.stellar.org/', self::NETWORK_PASSPHRASE_PUBLIC); - } - - /** - * @param $horizonBaseUrl - * @param $networkPassphrase - * @return ApiClient - */ - public static function newCustomClient($horizonBaseUrl, $networkPassphrase) - { - $apiClient = new ApiClient($horizonBaseUrl, $networkPassphrase); - $apiClient->isTestnet = true; - - return $apiClient; - } - - /** - * ApiClient constructor. - * - * @param $baseUrl string root URL of the horizon server, such as https://horizon-testnet.stellar.org/ - * @param $networkPassphrase string Passphrase used when signing transactions on the network - */ - public function __construct($baseUrl, $networkPassphrase) - { - $this->baseUrl = $baseUrl; - $this->httpClient = new Client([ - 'base_uri' => $baseUrl, - 'exceptions' => false, - ]); - $this->networkPassphrase = $networkPassphrase; - } - - /** - * todo: rename to getHashAsBytes - * - * @param TransactionBuilder $transactionBuilder - * @return string - */ - public function hash(TransactionBuilder $transactionBuilder) - { - return Hash::generate($this->getTransactionEnvelope($transactionBuilder)); - } - - public function getTransactionEnvelope(TransactionBuilder $transactionBuilder) - { - $transactionBytes = ''; - - $transactionBytes .= Hash::generate($this->networkPassphrase); - $transactionBytes .= XdrEncoder::unsignedInteger(TransactionEnvelope::TYPE_TX); - $transactionBytes .= $transactionBuilder->toXdr(); - - return $transactionBytes; - } - - /** - * @param TransactionBuilder $transactionBuilder - * @return string - */ - public function getHashAsString(TransactionBuilder $transactionBuilder) - { - return Hash::asString($this->getTransactionEnvelope($transactionBuilder)); - } - - /** - * Submits the transaction contained in the TransactionBuilder to the network - * - * @param TransactionBuilder $transactionBuilder - * @param $signingAccountSeedString - * @return PostTransactionResponse - */ - public function submitTransaction(TransactionBuilder $transactionBuilder, $signingAccountSeedString) - { - $transactionEnvelope = $transactionBuilder->sign($signingAccountSeedString); - - return $this->submitB64Transaction(base64_encode($transactionEnvelope->toXdr())); - } - - /** - * @param $base64TransactionEnvelope - * @return PostTransactionResponse - */ - public function submitB64Transaction($base64TransactionEnvelope) - { - return $this->postTransaction( - sprintf('/transactions'), - [ - 'tx' => $base64TransactionEnvelope, - ] - ); - } - - /** - * @param $accountId - * @return Account - */ - public function getAccount($accountId) - { - $account = Account::fromHorizonResponse($this->get(sprintf("/accounts/%s", $accountId))); - $account->setApiClient($this); - - return $account; - } - - /** - * @param $relativeUrl - * @return HorizonResponse - * @throws HorizonException - */ - public function get($relativeUrl) - { - try { - $res = $this->httpClient->get($relativeUrl); - } - catch (ClientException $e) { - // If the response can be json-decoded then it can be converted to a HorizonException - $decoded = null; - if ($e->getResponse()) { - $decoded = Json::mustDecode($e->getResponse()->getBody()); - throw HorizonException::fromRawResponse($relativeUrl, 'GET', $decoded, $e); - } - // No response, something else went wrong - else { - throw $e; - } - } - - return new HorizonResponse($res->getBody()); - } - - /** - * @param $relativeUrl - * @param array $parameters - * @return HorizonResponse - */ - public function post($relativeUrl, $parameters = array()) - { - $apiResponse = null; - - try { - $apiResponse = $this->httpClient->post($relativeUrl, [ 'form_params' => $parameters ]); - } - catch (ClientException $e) { - // If the response can be json-decoded then it can be converted to a HorizonException - $decoded = null; - if ($e->getResponse()) { - $decoded = Json::mustDecode($e->getResponse()->getBody()); - throw HorizonException::fromRawResponse($relativeUrl, 'POST', $decoded); - } - // No response, something else went wrong - else { - throw $e; - } - } - - return new HorizonResponse($apiResponse->getBody()); - } - - /** - * Streams Effect objects to $callback - * - * $callback should have arguments: - * Effect - * - * For example: - - $client = ApiClient::newPublicClient(); - $client->streamEffects('now', function(Effect $effect) { - printf('Effect type: %s' . PHP_EOL, $effect->getType()); - }); - * - * @param null $sinceCursor - * @param callable $callback - */ - public function streamEffects($sinceCursor = 'now', callable $callback = null) - { - $url = sprintf('/effects'); - $params = []; - - if ($sinceCursor) $params['cursor'] = $sinceCursor; - - if ($params) { - $url .= '?' . http_build_query($params); - } - - $this->getAndStream($url, function($rawData) use ($callback) { - $parsedObject = Effect::fromRawResponseData($rawData); - $parsedObject->setApiClient($this); - - $callback($parsedObject); - }); - } - - /** - * Streams Ledger objects to $callback - * - * $callback should have arguments: - * Ledger - * - * For example: - - $client = ApiClient::newPublicClient(); - $client->streamLedgers('now', function(Ledger $ledger) { - printf('[%s] Closed %s at %s with %s operations' . PHP_EOL, - (new \DateTime())->format('Y-m-d h:i:sa'), - $ledger->getId(), - $ledger->getClosedAt()->format('Y-m-d h:i:sa'), - $ledger->getOperationCount() - ); - }); - * - * @param null $sinceCursor - * @param callable $callback - */ - public function streamLedgers($sinceCursor = 'now', callable $callback = null) - { - $url = sprintf('/ledgers'); - $params = []; - - if ($sinceCursor) $params['cursor'] = $sinceCursor; - - if ($params) { - $url .= '?' . http_build_query($params); - } - - $this->getAndStream($url, function($rawData) use ($callback) { - $parsedObject = Ledger::fromRawResponseData($rawData); - $parsedObject->setApiClient($this); - - $callback($parsedObject); - }); - } - - /** - * Streams Operation objects to $callback - * - * $callback should have arguments: - * Operation - * - * For example: - - $client = ApiClient::newPublicClient(); - $client->streamOperations('now', function(Operation $operation) { - printf('Effect type: %s' . PHP_EOL, $effect->getType()); - }); - * - * @param null $sinceCursor - * @param callable $callback - */ - public function streamOperations($sinceCursor = 'now', callable $callback = null) - { - $url = sprintf('/operations'); - $params = []; - - if ($sinceCursor) $params['cursor'] = $sinceCursor; - - if ($params) { - $url .= '?' . http_build_query($params); - } - - $this->getAndStream($url, function($rawData) use ($callback) { - $parsedObject = Operation::fromRawResponseData($rawData); - $parsedObject->setApiClient($this); - - $callback($parsedObject); - }); - } - - /** - * Streams Payment or CreateAccount objects to $callback - * - * $callback should have arguments: - * AssetTransferInterface - * - * For example: - - $client = ApiClient::newPublicClient(); - $client->streamPayments('now', function(AssetTransferInterface $payment) { - printf('Payment: from %s to %s' . PHP_EOL, $payment->getFromAccountId(), $payment->getToAccountId()); - }); - * - * @param null $sinceCursor - * @param callable $callback - */ - public function streamPayments($sinceCursor = 'now', callable $callback = null) - { - $url = sprintf('/payments'); - $params = []; - - if ($sinceCursor) $params['cursor'] = $sinceCursor; - - if ($params) { - $url .= '?' . http_build_query($params); - } - - $this->getAndStream($url, function($rawData) use ($callback) { - switch ($rawData['type']) { - case 'create_account': - $parsedObject = CreateAccountOperation::fromRawResponseData($rawData); - break; - case 'payment': - $parsedObject = Payment::fromRawResponseData($rawData); - break; - case 'account_merge': - $parsedObject = AccountMergeOperation::fromRawResponseData($rawData); - break; - case 'path_payment': - $parsedObject = PathPayment::fromRawResponseData($rawData); - break; - } - - $parsedObject->setApiClient($this); - - $callback($parsedObject); - }); - } - - /** - * Streams Transaction objects to $callback - * - * $callback should have arguments: - * Transaction - * - * For example: - - $client = ApiClient::newPublicClient(); - $client->streamTransactions('now', function(Transaction $transaction) { - printf('Transaction id %s' . PHP_EOL, $transaction->getId()); - }); - * - * @param null $sinceCursor - * @param callable $callback - */ - public function streamTransactions($sinceCursor = 'now', callable $callback = null) - { - $url = sprintf('/transactions'); - $params = []; - - if ($sinceCursor) $params['cursor'] = $sinceCursor; - - if ($params) { - $url .= '?' . http_build_query($params); - } - - $this->getAndStream($url, function($rawData) use ($callback) { - $parsedObject = Transaction::fromRawResponseData($rawData); - $parsedObject->setApiClient($this); - - $callback($parsedObject); - }); - } - - /** - * @param $relativeUrl - * @param $callback - * @param $retryOnServerException bool If true, ignore ServerException errors and retry - */ - public function getAndStream($relativeUrl, $callback, $retryOnServerException = true) - { - while (true) { - try { - $response = $this->httpClient->get($relativeUrl, [ - 'stream' => true, - 'read_timeout' => null, - 'headers' => [ - 'Accept' => 'text/event-stream', - ] - ]); - - $body = $response->getBody(); - - while (!$body->eof()) { - $line = ''; - - $char = null; - while ($char != "\n") { - $line .= $char; - $char = $body->read(1); - } - - // Ignore empty lines - if (!$line) continue; - - // Ignore "data: hello" handshake - if (strpos($line, 'data: "hello"') === 0) continue; - - // Ignore lines that don't start with "data: " - $sentinel = 'data: '; - if (strpos($line, $sentinel) !== 0) continue; - - // Remove sentinel prefix - $json = substr($line, strlen($sentinel)); - - $decoded = json_decode($json, true); - if ($decoded) { - $callback($decoded); - } - } - - } - catch (ServerException $e) { - if (!$retryOnServerException) throw $e; - - // Delay for a bit before trying again - sleep(10); - } - } - } - - /** - * Special handling for the /transaction endpoint since we expect additional - * transaction-related fields to come back - * - * @param $relativeUrl - * @param array $parameters - * @return PostTransactionResponse - * @throws HorizonException - */ +isTestnet = true; + + return $apiClient; + } + + /** + * @return ApiClient + */ + public static function newPublicClient() + { + return new ApiClient('https://horizon.stellar.org/', self::NETWORK_PASSPHRASE_PUBLIC); + } + + /** + * @param $horizonBaseUrl + * @param $networkPassphrase + * @return ApiClient + */ + public static function newCustomClient($horizonBaseUrl, $networkPassphrase) + { + $apiClient = new ApiClient($horizonBaseUrl, $networkPassphrase); + $apiClient->isTestnet = true; + + return $apiClient; + } + + /** + * ApiClient constructor. + * + * @param $baseUrl string root URL of the horizon server, such as https://horizon-testnet.stellar.org/ + * @param $networkPassphrase string Passphrase used when signing transactions on the network + */ + public function __construct($baseUrl, $networkPassphrase) + { + $this->baseUrl = $baseUrl; + $this->httpClient = new Client([ + 'base_uri' => $baseUrl, + 'exceptions' => false, + ]); + $this->networkPassphrase = $networkPassphrase; + } + + /** + * todo: rename to getHashAsBytes + * + * @param TransactionBuilder $transactionBuilder + * @return string + */ + public function hash(TransactionBuilder $transactionBuilder) + { + return Hash::generate($this->getTransactionEnvelope($transactionBuilder)); + } + + public function getTransactionEnvelope(TransactionBuilder $transactionBuilder) + { + $transactionBytes = ''; + + $transactionBytes .= Hash::generate($this->networkPassphrase); + $transactionBytes .= XdrEncoder::unsignedInteger(TransactionEnvelope::TYPE_TX); + $transactionBytes .= $transactionBuilder->toXdr(); + + return $transactionBytes; + } + + /** + * @param TransactionBuilder $transactionBuilder + * @return string + */ + public function getHashAsString(TransactionBuilder $transactionBuilder) + { + return Hash::asString($this->getTransactionEnvelope($transactionBuilder)); + } + + /** + * Submits the transaction contained in the TransactionBuilder to the network + * + * @param TransactionBuilder $transactionBuilder + * @param $signingAccountSeedString + * @return PostTransactionResponse + */ + public function submitTransaction(TransactionBuilder $transactionBuilder, $signingAccountSeedString) + { + $transactionEnvelope = $transactionBuilder->sign($signingAccountSeedString); + + return $this->submitB64Transaction(base64_encode($transactionEnvelope->toXdr())); + } + + /** + * @param $base64TransactionEnvelope + * @return PostTransactionResponse + */ + public function submitB64Transaction($base64TransactionEnvelope) + { + return $this->postTransaction( + sprintf('/transactions'), + [ + 'tx' => $base64TransactionEnvelope, + ] + ); + } + + /** + * @param $accountId + * @return Account + */ + public function getAccount($accountId) + { + $account = Account::fromHorizonResponse($this->get(sprintf("/accounts/%s", $accountId))); + $account->setApiClient($this); + + return $account; + } + + /** + * @param $relativeUrl + * @return HorizonResponse + * @throws HorizonException + */ + public function get($relativeUrl) + { + try { + $res = $this->httpClient->get($relativeUrl); + } + catch (ClientException $e) { + // If the response can be json-decoded then it can be converted to a HorizonException + $decoded = null; + if ($e->getResponse()) { + $decoded = Json::mustDecode($e->getResponse()->getBody()); + throw HorizonException::fromRawResponse($relativeUrl, 'GET', $decoded, $e); + } + // No response, something else went wrong + else { + throw $e; + } + } + + return new HorizonResponse($res->getBody()); + } + + /** + * @param $relativeUrl + * @param array $parameters + * @return HorizonResponse + */ + public function post($relativeUrl, $parameters = array()) + { + $apiResponse = null; + + try { + $apiResponse = $this->httpClient->post($relativeUrl, [ 'form_params' => $parameters ]); + } + catch (ClientException $e) { + // If the response can be json-decoded then it can be converted to a HorizonException + $decoded = null; + if ($e->getResponse()) { + $decoded = Json::mustDecode($e->getResponse()->getBody()); + throw HorizonException::fromRawResponse($relativeUrl, 'POST', $decoded); + } + // No response, something else went wrong + else { + throw $e; + } + } + + return new HorizonResponse($apiResponse->getBody()); + } + + /** + * Streams Effect objects to $callback + * + * $callback should have arguments: + * Effect + * + * For example: + + $client = ApiClient::newPublicClient(); + $client->streamEffects('now', function(Effect $effect) { + printf('Effect type: %s' . PHP_EOL, $effect->getType()); + }); + * + * @param null $sinceCursor + * @param callable $callback + */ + public function streamEffects($sinceCursor = 'now', callable $callback = null) + { + $url = sprintf('/effects'); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + + if ($params) { + $url .= '?' . http_build_query($params); + } + + $this->getAndStream($url, function($rawData) use ($callback) { + $parsedObject = Effect::fromRawResponseData($rawData); + $parsedObject->setApiClient($this); + + $callback($parsedObject); + }); + } + + /** + * Streams Ledger objects to $callback + * + * $callback should have arguments: + * Ledger + * + * For example: + + $client = ApiClient::newPublicClient(); + $client->streamLedgers('now', function(Ledger $ledger) { + printf('[%s] Closed %s at %s with %s operations' . PHP_EOL, + (new \DateTime())->format('Y-m-d h:i:sa'), + $ledger->getId(), + $ledger->getClosedAt()->format('Y-m-d h:i:sa'), + $ledger->getOperationCount() + ); + }); + * + * @param null $sinceCursor + * @param callable $callback + */ + public function streamLedgers($sinceCursor = 'now', callable $callback = null) + { + $url = sprintf('/ledgers'); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + + if ($params) { + $url .= '?' . http_build_query($params); + } + + $this->getAndStream($url, function($rawData) use ($callback) { + $parsedObject = Ledger::fromRawResponseData($rawData); + $parsedObject->setApiClient($this); + + $callback($parsedObject); + }); + } + + /** + * Streams Operation objects to $callback + * + * $callback should have arguments: + * Operation + * + * For example: + + $client = ApiClient::newPublicClient(); + $client->streamOperations('now', function(Operation $operation) { + printf('Effect type: %s' . PHP_EOL, $effect->getType()); + }); + * + * @param null $sinceCursor + * @param callable $callback + */ + public function streamOperations($sinceCursor = 'now', callable $callback = null) + { + $url = sprintf('/operations'); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + + if ($params) { + $url .= '?' . http_build_query($params); + } + + $this->getAndStream($url, function($rawData) use ($callback) { + $parsedObject = Operation::fromRawResponseData($rawData); + $parsedObject->setApiClient($this); + + $callback($parsedObject); + }); + } + + /** + * Streams Payment or CreateAccount objects to $callback + * + * $callback should have arguments: + * AssetTransferInterface + * + * For example: + + $client = ApiClient::newPublicClient(); + $client->streamPayments('now', function(AssetTransferInterface $payment) { + printf('Payment: from %s to %s' . PHP_EOL, $payment->getFromAccountId(), $payment->getToAccountId()); + }); + * + * @param null $sinceCursor + * @param callable $callback + */ + public function streamPayments($sinceCursor = 'now', callable $callback = null) + { + $url = sprintf('/payments'); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + + if ($params) { + $url .= '?' . http_build_query($params); + } + + $this->getAndStream($url, function($rawData) use ($callback) { + switch ($rawData['type']) { + case 'create_account': + $parsedObject = CreateAccountOperation::fromRawResponseData($rawData); + break; + case 'payment': + $parsedObject = Payment::fromRawResponseData($rawData); + break; + case 'account_merge': + $parsedObject = AccountMergeOperation::fromRawResponseData($rawData); + break; + case 'path_payment': + $parsedObject = PathPayment::fromRawResponseData($rawData); + break; + } + + $parsedObject->setApiClient($this); + + $callback($parsedObject); + }); + } + + /** + * Streams Transaction objects to $callback + * + * $callback should have arguments: + * Transaction + * + * For example: + + $client = ApiClient::newPublicClient(); + $client->streamTransactions('now', function(Transaction $transaction) { + printf('Transaction id %s' . PHP_EOL, $transaction->getId()); + }); + * + * @param null $sinceCursor + * @param callable $callback + */ + public function streamTransactions($sinceCursor = 'now', callable $callback = null) + { + $url = sprintf('/transactions'); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + + if ($params) { + $url .= '?' . http_build_query($params); + } + + $this->getAndStream($url, function($rawData) use ($callback) { + $parsedObject = Transaction::fromRawResponseData($rawData); + $parsedObject->setApiClient($this); + + $callback($parsedObject); + }); + } + + /** + * @param $relativeUrl + * @param $callback + * @param $retryOnServerException bool If true, ignore ServerException errors and retry + */ + public function getAndStream($relativeUrl, $callback, $retryOnServerException = true) + { + while (true) { + try { + $response = $this->httpClient->get($relativeUrl, [ + 'stream' => true, + 'read_timeout' => null, + 'headers' => [ + 'Accept' => 'text/event-stream', + ] + ]); + + $body = $response->getBody(); + + while (!$body->eof()) { + $line = ''; + + $char = null; + while ($char != "\n") { + $line .= $char; + $char = $body->read(1); + } + + // Ignore empty lines + if (!$line) continue; + + // Ignore "data: hello" handshake + if (strpos($line, 'data: "hello"') === 0) continue; + + // Ignore lines that don't start with "data: " + $sentinel = 'data: '; + if (strpos($line, $sentinel) !== 0) continue; + + // Remove sentinel prefix + $json = substr($line, strlen($sentinel)); + + $decoded = json_decode($json, true); + if ($decoded) { + $callback($decoded); + } + } + + } + catch (ServerException $e) { + if (!$retryOnServerException) throw $e; + + // Delay for a bit before trying again + sleep(10); + } + } + } + + /** + * Special handling for the /transaction endpoint since we expect additional + * transaction-related fields to come back + * + * @param $relativeUrl + * @param array $parameters + * @return PostTransactionResponse + * @throws HorizonException + */ protected function postTransaction($relativeUrl, $parameters = array()) { $apiResponse = null; @@ -505,55 +505,62 @@ protected function postTransaction($relativeUrl, $parameters = array()) } } - return new PostTransactionResponse($apiResponse->getBody()); - } - - /** - * @return string - */ - public function getNetworkPassphrase() - { - return $this->networkPassphrase; - } - - /** - * @param string $networkPassphrase - */ - public function setNetworkPassphrase($networkPassphrase) - { - $this->networkPassphrase = $networkPassphrase; - } - - /** - * @return string - */ - public function getBaseUrl() - { - return $this->baseUrl; - } - - /** - * @param string $baseUrl - */ - public function setBaseUrl($baseUrl) - { - $this->baseUrl = $baseUrl; - } - - /** - * @return Client - */ - public function getHttpClient() - { - return $this->httpClient; - } + // With Guzzle exceptions disabled, failures return a response with 4xx status. + // Detect that and throw a PostTransactionException to match expected behavior. + if ($apiResponse->getStatusCode() >= 400) { + $decoded = Json::mustDecode($apiResponse->getBody()); + throw PostTransactionException::fromRawResponse($relativeUrl, 'POST', $decoded); + } - /** - * @param Client $httpClient - */ - public function setHttpClient($httpClient) - { - $this->httpClient = $httpClient; + return new PostTransactionResponse($apiResponse->getBody()); } - -} \ No newline at end of file + + /** + * @return string + */ + public function getNetworkPassphrase() + { + return $this->networkPassphrase; + } + + /** + * @param string $networkPassphrase + */ + public function setNetworkPassphrase($networkPassphrase) + { + $this->networkPassphrase = $networkPassphrase; + } + + /** + * @return string + */ + public function getBaseUrl() + { + return $this->baseUrl; + } + + /** + * @param string $baseUrl + */ + public function setBaseUrl($baseUrl) + { + $this->baseUrl = $baseUrl; + } + + /** + * @return Client + */ + public function getHttpClient() + { + return $this->httpClient; + } + + /** + * @param Client $httpClient + */ + public function setHttpClient($httpClient) + { + $this->httpClient = $httpClient; + } + +} diff --git a/src/Horizon/Exception/HorizonException.php b/src/Horizon/Exception/HorizonException.php index 2ff98f4..ce2ad76 100644 --- a/src/Horizon/Exception/HorizonException.php +++ b/src/Horizon/Exception/HorizonException.php @@ -1,336 +1,338 @@ -title = $title; - $exception->requestedUrl = $requestedUrl; - $exception->httpMethod = $httpMethod; - - if (isset($raw['type'])) $exception->type = $raw['type']; - if (isset($raw['status'])) $exception->httpStatusCode = $raw['status']; - if (isset($raw['detail'])) $exception->detail = $raw['detail']; - if (!empty($raw['extras']['result_codes']['operations'])) { - $exception->operationResultCodes = $raw['extras']['result_codes']['operations']; - } - if (!empty($raw['extras']['result_codes']['transaction'])) { - $exception->transactionResultCode = $raw['extras']['result_codes']['transaction']; - } - - // Message can contain better info after we've filled out more fields - $exception->message = $exception->buildMessage(); - - $exception->raw = $raw; - $exception->clientException = $clientException; - - return $exception; - } - - /** - * @param string $title - * @param Throwable|null $previous - */ +title = $title; + $exception->requestedUrl = $requestedUrl; + $exception->httpMethod = $httpMethod; + + if (isset($raw['type'])) $exception->type = $raw['type']; + if (isset($raw['status'])) $exception->httpStatusCode = $raw['status']; + if (isset($raw['detail'])) $exception->detail = $raw['detail']; + if (!empty($raw['extras']['result_codes']['operations'])) { + $exception->operationResultCodes = $raw['extras']['result_codes']['operations']; + } + if (!empty($raw['extras']['result_codes']['transaction'])) { + $exception->transactionResultCode = $raw['extras']['result_codes']['transaction']; + } + + // Message can contain better info after we've filled out more fields + $exception->message = $exception->buildMessage(); + + $exception->raw = $raw; + $exception->clientException = $clientException; + + return $exception; + } + + /** + * @param string $title + * @param Throwable|null $previous + */ public function __construct($title, Throwable $previous = null) { - parent::__construct($title, 0, 1, $previous->getFile(), $previous->getLine(), $previous); - } - - /** - * @return string - */ - protected function buildMessage() { - // Additional data used to help the user resolve the error - $hint = ''; - - $message = sprintf('[%s] %s: %s (Requested URL: %s %s)', - $this->httpStatusCode, - $this->title, - $this->detail, - $this->httpMethod, - $this->requestedUrl - ); - - if ($this->transactionResultCode) { - $message .= sprintf(" Tx Result: %s", $this->transactionResultCode); - } - if (!empty($this->operationResultCodes)) { - $message .= sprintf(" Op Results: %s", print_r($this->operationResultCodes,true)); - } - - // Rate limit exceeded - if ('429' == $this->httpStatusCode) { - // todo: check response headers and provide better error message - } - - return $message; - } - - /** - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * @param string $type - */ - public function setType($type) - { - $this->type = $type; - } - - /** - * @return string - */ - public function getTitle() - { - return $this->title; - } - - /** - * @param string $title - */ - public function setTitle($title) - { - $this->title = $title; - } - - /** - * @return string - */ - public function getDetail() - { - return $this->detail; - } - - /** - * @param string $detail - */ - public function setDetail($detail) - { - $this->detail = $detail; - } - - /** - * @return string - */ - public function getInstance() - { - return $this->instance; - } - - /** - * @param string $instance - */ - public function setInstance($instance) - { - $this->instance = $instance; - } - - /** - * @return string - */ - public function getRequestedUrl() - { - return $this->requestedUrl; - } - - /** - * @param string $requestedUrl - */ - public function setRequestedUrl($requestedUrl) - { - $this->requestedUrl = $requestedUrl; - } - - /** - * @return int - */ - public function getHttpStatusCode() - { - return $this->httpStatusCode; - } - - /** - * @param int $httpStatusCode - */ - public function setHttpStatusCode($httpStatusCode) - { - $this->httpStatusCode = $httpStatusCode; - } - - /** - * @return ClientException - */ - public function getClientException() - { - return $this->clientException; - } - - /** - * @param ClientException $clientException - */ - public function setClientException($clientException) - { - $this->clientException = $clientException; - } - - /** - * Get the result codes from Horizon Response. - * - * @return array - */ - function getOperationResultCodes() - { - return $this->operationResultCodes; - } - - /** - * Set the result codes from Horizon Response. - * - * @param array $operationResultCodes - */ - function setOperationResultCodes($operationResultCodes) - { - $this->operationResultCodes = $operationResultCodes; - } - - /** - * @return string - */ - public function getHttpMethod() - { - return $this->httpMethod; - } - - /** - * @param string $httpMethod - */ - public function setHttpMethod($httpMethod) - { - $this->httpMethod = $httpMethod; - } - - /** - * @return array - */ - public function getRaw() - { - return $this->raw; - } - - /** - * @param array $raw - */ - public function setRaw($raw) - { - $this->raw = $raw; - } - - /** - * @return string - */ - public function getTransactionResultCode() - { - return $this->transactionResultCode; - } - - /** - * @param string $transactionResultCode - */ - public function setTransactionResultCode($transactionResultCode) - { - $this->transactionResultCode = $transactionResultCode; + $file = $previous ? $previous->getFile() : __FILE__; + $line = $previous ? $previous->getLine() : __LINE__; + parent::__construct($title, 0, 1, $file, $line, $previous); } -} \ No newline at end of file + + /** + * @return string + */ + protected function buildMessage() { + // Additional data used to help the user resolve the error + $hint = ''; + + $message = sprintf('[%s] %s: %s (Requested URL: %s %s)', + $this->httpStatusCode, + $this->title, + $this->detail, + $this->httpMethod, + $this->requestedUrl + ); + + if ($this->transactionResultCode) { + $message .= sprintf(" Tx Result: %s", $this->transactionResultCode); + } + if (!empty($this->operationResultCodes)) { + $message .= sprintf(" Op Results: %s", print_r($this->operationResultCodes,true)); + } + + // Rate limit exceeded + if ('429' == $this->httpStatusCode) { + // todo: check response headers and provide better error message + } + + return $message; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @param string $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle($title) + { + $this->title = $title; + } + + /** + * @return string + */ + public function getDetail() + { + return $this->detail; + } + + /** + * @param string $detail + */ + public function setDetail($detail) + { + $this->detail = $detail; + } + + /** + * @return string + */ + public function getInstance() + { + return $this->instance; + } + + /** + * @param string $instance + */ + public function setInstance($instance) + { + $this->instance = $instance; + } + + /** + * @return string + */ + public function getRequestedUrl() + { + return $this->requestedUrl; + } + + /** + * @param string $requestedUrl + */ + public function setRequestedUrl($requestedUrl) + { + $this->requestedUrl = $requestedUrl; + } + + /** + * @return int + */ + public function getHttpStatusCode() + { + return $this->httpStatusCode; + } + + /** + * @param int $httpStatusCode + */ + public function setHttpStatusCode($httpStatusCode) + { + $this->httpStatusCode = $httpStatusCode; + } + + /** + * @return ClientException + */ + public function getClientException() + { + return $this->clientException; + } + + /** + * @param ClientException $clientException + */ + public function setClientException($clientException) + { + $this->clientException = $clientException; + } + + /** + * Get the result codes from Horizon Response. + * + * @return array + */ + function getOperationResultCodes() + { + return $this->operationResultCodes; + } + + /** + * Set the result codes from Horizon Response. + * + * @param array $operationResultCodes + */ + function setOperationResultCodes($operationResultCodes) + { + $this->operationResultCodes = $operationResultCodes; + } + + /** + * @return string + */ + public function getHttpMethod() + { + return $this->httpMethod; + } + + /** + * @param string $httpMethod + */ + public function setHttpMethod($httpMethod) + { + $this->httpMethod = $httpMethod; + } + + /** + * @return array + */ + public function getRaw() + { + return $this->raw; + } + + /** + * @param array $raw + */ + public function setRaw($raw) + { + $this->raw = $raw; + } + + /** + * @return string + */ + public function getTransactionResultCode() + { + return $this->transactionResultCode; + } + + /** + * @param string $transactionResultCode + */ + public function setTransactionResultCode($transactionResultCode) + { + $this->transactionResultCode = $transactionResultCode; + } +} diff --git a/src/Horizon/Exception/PostTransactionException.php b/src/Horizon/Exception/PostTransactionException.php index 274e376..685c530 100644 --- a/src/Horizon/Exception/PostTransactionException.php +++ b/src/Horizon/Exception/PostTransactionException.php @@ -1,70 +1,70 @@ -result = TransactionResult::fromXdr($xdr); - } - - return $postTransactionEx; - } - - /** - * @param HorizonException $horizonException - * @return PostTransactionException - */ - public static function fromHorizonException(HorizonException $horizonException) - { - $ex = new PostTransactionException($horizonException->getTitle(), $horizonException->getPrevious()); - - $ex->requestedUrl = $horizonException->getRequestedUrl(); - $ex->httpMethod = $horizonException->getHttpMethod(); - $ex->type = $horizonException->getType(); - $ex->httpStatusCode = $horizonException->getHttpStatusCode(); - $ex->detail = $horizonException->getDetail(); - $ex->operationResultCodes = $horizonException->getOperationResultCodes(); - $ex->transactionResultCode = $horizonException->getTransactionResultCode(); - $ex->message = $horizonException->getMessage(); - $ex->raw = $horizonException->getRaw(); - $ex->clientException = $horizonException->getClientException(); - - return $ex; - } - - /** - * @return TransactionResult - */ - public function getResult() - { - return $this->result; - } - - /** - * @param TransactionResult $result - */ - public function setResult($result) - { - $this->result = $result; - } +result = TransactionResult::fromXdr($xdr); + } + + return $postTransactionEx; + } + + /** + * @param HorizonException $horizonException + * @return PostTransactionException + */ + public static function fromHorizonException(HorizonException $horizonException) + { + $ex = new PostTransactionException($horizonException->getTitle(), $horizonException->getPrevious()); + + $ex->requestedUrl = $horizonException->getRequestedUrl(); + $ex->httpMethod = $horizonException->getHttpMethod(); + $ex->type = $horizonException->getType(); + $ex->httpStatusCode = $horizonException->getHttpStatusCode(); + $ex->detail = $horizonException->getDetail(); + $ex->operationResultCodes = $horizonException->getOperationResultCodes(); + $ex->transactionResultCode = $horizonException->getTransactionResultCode(); + $ex->message = $horizonException->getMessage(); + $ex->raw = $horizonException->getRaw(); + $ex->clientException = $horizonException->getClientException(); + + return $ex; + } + + /** + * @return TransactionResult + */ + public function getResult() + { + return $this->result; + } + + /** + * @param TransactionResult $result + */ + public function setResult($result) + { + $this->result = $result; + } } \ No newline at end of file diff --git a/src/Keypair.php b/src/Keypair.php index 54d5642..edab61b 100755 --- a/src/Keypair.php +++ b/src/Keypair.php @@ -1,276 +1,276 @@ -setPublicKey($base32String); - - return $keypair; - } - - /** - * Creates a new keypair from a mnemonic, passphrase (optional) and index (defaults to 0) - * - * For more details, see https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md - * - * @param $mnemonic - * @param string $passphrase - * @param int $index - * @return Keypair - */ - public static function newFromMnemonic($mnemonic, $passphrase = '', $index = 0) - { - $bip39 = new Bip39(); - $seedBytes = $bip39->mnemonicToSeedBytesWithErrorChecking($mnemonic, $passphrase); - - $masterNode = HdNode::newMasterNode($seedBytes); - - $accountNode = $masterNode->derivePath(sprintf("m/44'/148'/%s'", $index)); - - return static::newFromRawSeed($accountNode->getPrivateKeyBytes()); - } - - public function __construct($seedString = null) - { - if ($seedString) { - $this->setSeed($seedString); - } - } - - /** - * @param $value - * @return DecoratedSignature - */ - public function signDecorated($value) - { - $this->requirePrivateKey(); - - return new DecoratedSignature( - $this->getHint(), - $this->sign($value) - ); - } - - /** - * Signs the specified $value with the private key - * - * @param $value - * @return string - raw bytes representing the signature - */ - public function sign($value) - { - $this->requirePrivateKey(); - - return Ed25519::sign_detached($value, $this->getEd25519SecretKey()); - } - - /** - * @param $signature - * @param $message - * @return bool - * @throws \Exception - */ - public function verifySignature($signature, $message) - { - return Ed25519::verify_detached($signature, $message, $this->publicKey); - } - - /** - * @param $base32String string GABC... - */ - public function setPublicKey($base32String) - { - // Clear out all private key fields - $this->privateKey = null; - - $this->publicKey = AddressableKey::getRawBytesFromBase32AccountId($base32String); - $this->publicKeyString = $base32String; - } - - /** - * @param $base32SeedString - */ - public function setSeed($base32SeedString) - { - $this->seed = $base32SeedString; - $this->privateKey = AddressableKey::getRawBytesFromBase32Seed($base32SeedString); - $this->publicKeyString = AddressableKey::addressFromRawSeed($this->privateKey); - $this->publicKey = AddressableKey::getRawBytesFromBase32AccountId($this->publicKeyString); - } - - /** - * Returns the last 4 characters of the public key - * - * @return string - */ - public function getHint() - { - return substr($this->publicKey, -4); - } - - /** - * Returns the raw bytes of the checksum for the public key - * - * @return string - */ - public function getPublicKeyChecksum() - { - $checksumBytes = substr($this->getPublicKeyBytes(), -2); - - $unpacked = unpack('v', $checksumBytes); - - return array_shift($unpacked); - } - - /** - * Returns the base-32 encoded private key (S...) - * @return string - * @throws \ErrorException - */ - public function getSecret() - { - $this->requirePrivateKey(); - - return $this->seed; - } - - /** - * @return bool|string - * @throws \ErrorException - */ - public function getPrivateKeyBytes() - { - $this->requirePrivateKey(); - - return AddressableKey::getRawBytesFromBase32Seed($this->seed); - } - - /** - * Returns the base-32 encoded public key (G...) - * @return string - */ - public function getPublicKey() - { - return $this->publicKeyString; - } - - /** - * @return string - */ - public function getPublicKeyBytes() - { - return $this->publicKey; - } - - /** - * Returns the base-32 encoded public key (G...) - * @return string - */ - public function getAccountId() - { - return $this->publicKeyString; - } - - /** - * Used to ensure the private key has been specified for this keypair - * - * @throws \ErrorException - */ - protected function requirePrivateKey() - { - if (!$this->privateKey) throw new \ErrorException('Private key is required to perform this operation'); - } - - protected function getEd25519SecretKey() - { - $this->requirePrivateKey(); - - $pk = ''; - $sk = ''; - - Ed25519::seed_keypair($pk, $sk, $this->privateKey); - - return $sk; - } +setPublicKey($base32String); + + return $keypair; + } + + /** + * Creates a new keypair from a mnemonic, passphrase (optional) and index (defaults to 0) + * + * For more details, see https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md + * + * @param $mnemonic + * @param string $passphrase + * @param int $index + * @return Keypair + */ + public static function newFromMnemonic($mnemonic, $passphrase = '', $index = 0) + { + $bip39 = new Bip39(); + $seedBytes = $bip39->mnemonicToSeedBytesWithErrorChecking($mnemonic, $passphrase); + + $masterNode = HdNode::newMasterNode($seedBytes); + + $accountNode = $masterNode->derivePath(sprintf("m/44'/148'/%s'", $index)); + + return static::newFromRawSeed($accountNode->getPrivateKeyBytes()); + } + + public function __construct($seedString = null) + { + if ($seedString) { + $this->setSeed($seedString); + } + } + + /** + * @param $value + * @return DecoratedSignature + */ + public function signDecorated($value) + { + $this->requirePrivateKey(); + + return new DecoratedSignature( + $this->getHint(), + $this->sign($value) + ); + } + + /** + * Signs the specified $value with the private key + * + * @param $value + * @return string - raw bytes representing the signature + */ + public function sign($value) + { + $this->requirePrivateKey(); + + return Ed25519::sign_detached($value, $this->getEd25519SecretKey()); + } + + /** + * @param $signature + * @param $message + * @return bool + * @throws \Exception + */ + public function verifySignature($signature, $message) + { + return Ed25519::verify_detached($signature, $message, $this->publicKey); + } + + /** + * @param $base32String string GABC... + */ + public function setPublicKey($base32String) + { + // Clear out all private key fields + $this->privateKey = null; + + $this->publicKey = AddressableKey::getRawBytesFromBase32AccountId($base32String); + $this->publicKeyString = $base32String; + } + + /** + * @param $base32SeedString + */ + public function setSeed($base32SeedString) + { + $this->seed = $base32SeedString; + $this->privateKey = AddressableKey::getRawBytesFromBase32Seed($base32SeedString); + $this->publicKeyString = AddressableKey::addressFromRawSeed($this->privateKey); + $this->publicKey = AddressableKey::getRawBytesFromBase32AccountId($this->publicKeyString); + } + + /** + * Returns the last 4 characters of the public key + * + * @return string + */ + public function getHint() + { + return substr($this->publicKey, -4); + } + + /** + * Returns the raw bytes of the checksum for the public key + * + * @return string + */ + public function getPublicKeyChecksum() + { + $checksumBytes = substr($this->getPublicKeyBytes(), -2); + + $unpacked = unpack('v', $checksumBytes); + + return array_shift($unpacked); + } + + /** + * Returns the base-32 encoded private key (S...) + * @return string + * @throws \ErrorException + */ + public function getSecret() + { + $this->requirePrivateKey(); + + return $this->seed; + } + + /** + * @return bool|string + * @throws \ErrorException + */ + public function getPrivateKeyBytes() + { + $this->requirePrivateKey(); + + return AddressableKey::getRawBytesFromBase32Seed($this->seed); + } + + /** + * Returns the base-32 encoded public key (G...) + * @return string + */ + public function getPublicKey() + { + return $this->publicKeyString; + } + + /** + * @return string + */ + public function getPublicKeyBytes() + { + return $this->publicKey; + } + + /** + * Returns the base-32 encoded public key (G...) + * @return string + */ + public function getAccountId() + { + return $this->publicKeyString; + } + + /** + * Used to ensure the private key has been specified for this keypair + * + * @throws \ErrorException + */ + protected function requirePrivateKey() + { + if (!$this->privateKey) throw new \ErrorException('Private key is required to perform this operation'); + } + + protected function getEd25519SecretKey() + { + $this->requirePrivateKey(); + + $pk = ''; + $sk = ''; + + Ed25519::seed_keypair($pk, $sk, $this->privateKey); + + return $sk; + } } \ No newline at end of file diff --git a/src/Model/Account.php b/src/Model/Account.php index 1b4ab4f..98f2186 100755 --- a/src/Model/Account.php +++ b/src/Model/Account.php @@ -1,249 +1,269 @@ -getSequenceAsBigInteger() - * @var string - */ - private $sequence; - - private $subentryCount; - - /** - * @var array|AssetAmount[] - */ - private $balances; - - private $thresholds; - - private $signers; - - private $data; - - /** - * @param HorizonResponse $response - * @return Account - */ - public static function fromHorizonResponse(HorizonResponse $response) +use ZuluCrypto\StellarSdk\Model\Payment; +use ZuluCrypto\StellarSdk\Model\PathPayment; +use ZuluCrypto\StellarSdk\Model\CreateAccountOperation; +use ZuluCrypto\StellarSdk\Model\AccountMergeOperation; +use ZuluCrypto\StellarSdk\Util\MathSafety; +use ZuluCrypto\StellarSdk\XdrModel\Asset; +use ZuluCrypto\StellarSdk\XdrModel\Operation\PaymentOp; + +/** + * See: https://www.stellar.org/developers/horizon/reference/resources/account.html + * + * Account viewer: + * https://www.stellar.org/laboratory/#explorer + */ +class Account extends RestApiModel +{ + protected $id; + + private $accountId; + + /** + * NOTE: for the BigInteger representation of this, see $this->getSequenceAsBigInteger() + * @var string + */ + private $sequence; + + private $subentryCount; + + /** + * @var array|AssetAmount[] + */ + private $balances; + + private $thresholds; + + private $signers; + + private $data; + + /** + * @param HorizonResponse $response + * @return Account + */ + public static function fromHorizonResponse(HorizonResponse $response) + { + $rawData = $response->getRawData(); + + // 404 means the account does not currently exist (it may have been merged) + if (isset($rawData['status']) && $rawData['status'] == 404) { + throw new \InvalidArgumentException('Account does not exist'); + } + + // Generic catch for other errors + if (isset($rawData['status']) && $rawData['status'] !== 200) { + throw new \InvalidArgumentException('Cannot create account due to error response'); + } + + $object = new Account($rawData['id']); + + $object->accountId = $rawData['account_id']; + $object->sequence = $rawData['sequence']; + $object->subentryCount = $rawData['subentry_count']; + $object->thresholds = $rawData['thresholds']; + $object->data = []; + if (isset($rawData['data'])) { + foreach ($rawData['data'] as $key => $value) { + $object->data[$key] = base64_decode($value); + } + } + + if (isset($rawData['balances'])) { + foreach ($rawData['balances'] as $rawBalance) { + $balance = new AssetAmount($rawBalance['balance'], $rawBalance['asset_type']); + + if (!$balance->isNativeAsset()) { + $balance->setAssetCode($rawBalance['asset_code']); + $balance->setAssetIssuerAccountId($rawBalance['asset_issuer']); + $balance->setLimit($rawBalance['limit']); + } + + $object->balances[] = $balance; + } + } + + return $object; + } + + /** + * Returns true if the specified account ID (G....) passes basic validity checks + * + * Note that this doesn't necessarily mean the account is funded or exists + * on the network. To check that, use the Server::getAccount() method. + * + * @param $accountId + * @return bool + */ + public static function isValidAccount($accountId) { - $rawData = $response->getRawData(); - - // 404 means the account does not currently exist (it may have been merged) - if (isset($rawData['status']) && $rawData['status'] == 404) { - throw new \InvalidArgumentException('Account does not exist'); - } - - // Generic catch for other errors - if (isset($rawData['status']) && $rawData['status'] !== 200) { - throw new \InvalidArgumentException('Cannot create account due to error response'); - } - - $object = new Account($rawData['id']); - - $object->accountId = $rawData['account_id']; - $object->sequence = $rawData['sequence']; - $object->subentryCount = $rawData['subentry_count']; - $object->thresholds = $rawData['thresholds']; - $object->data = []; - if (isset($rawData['data'])) { - foreach ($rawData['data'] as $key => $value) { - $object->data[$key] = base64_decode($value); - } - } - - if (isset($rawData['balances'])) { - foreach ($rawData['balances'] as $rawBalance) { - $balance = new AssetAmount($rawBalance['balance'], $rawBalance['asset_type']); - - if (!$balance->isNativeAsset()) { - $balance->setAssetCode($rawBalance['asset_code']); - $balance->setAssetIssuerAccountId($rawBalance['asset_issuer']); - $balance->setLimit($rawBalance['limit']); - } - - $object->balances[] = $balance; - } + if (!is_string($accountId) || $accountId === '') { + return false; } - return $object; - } - - /** - * Returns true if the specified account ID (G....) passes basic validity checks - * - * Note that this doesn't necessarily mean the account is funded or exists - * on the network. To check that, use the Server::getAccount() method. - * - * @param $accountId - * @return bool - */ - public static function isValidAccount($accountId) - { // Validate that keypair passes checksum try { $keypair = Keypair::newFromPublicKey($accountId); - } catch (\Exception $e) { + } catch (\Throwable $e) { return false; } return true; } - - public function __construct($id) - { - $this->id = $id; - - $this->balances = []; - } - - /** - * @param $toAccountId - * @param $amount - * @param string|string[] $signingKeys - * @return HorizonResponse - * @throws \ErrorException - */ - public function sendNativeAsset($toAccountId, $amount, $signingKeys) - { - $payment = Payment::newNativeAssetPayment($toAccountId, $amount, $this->accountId); - - return $this->sendPayment($payment, $signingKeys); - } - - /** - * @param Payment $payment - * @param $signingKeys - * @return HorizonResponse - * @throws \ErrorException - */ - public function sendPayment(Payment $payment, $signingKeys) - { - if ($payment->isNativeAsset()) { - $paymentOp = PaymentOp::newNativePayment($payment->getDestinationAccountId(), $payment->getAmount()->getBalanceAsStroops()); - } - else { - throw new \ErrorException('Not implemented'); - } - - $transaction = (new TransactionBuilder($this->accountId)) - ->setApiClient($this->apiClient) - ->addOperation( - $paymentOp - ) - ; - - return $transaction->submit($signingKeys); - } - - /** - * @param null $sinceCursor - * @param int $limit - * @return Transaction[] - */ - public function getTransactions($sinceCursor = null, $limit = 50) - { - $transactions = []; - - $url = sprintf('/accounts/%s/transactions', $this->accountId); - $params = []; - - if ($sinceCursor) $params['cursor'] = $sinceCursor; - if ($limit) $params['limit'] = $limit; - - if ($params) { - $url .= '?' . http_build_query($params); - } - - $response = $this->apiClient->get($url); - $rawTransactions = $response->getRecords(); - - foreach ($rawTransactions as $rawTransaction) { - $transaction = Transaction::fromRawResponseData($rawTransaction); - $transaction->setApiClient($this->getApiClient()); - - $transactions[] = $transaction; - } - - return $transactions; - } - + + public function __construct($id) + { + $this->id = $id; + + $this->balances = []; + } + + /** + * @param $toAccountId + * @param $amount + * @param string|string[] $signingKeys + * @return HorizonResponse + * @throws \ErrorException + */ + public function sendNativeAsset($toAccountId, $amount, $signingKeys) + { + $payment = Payment::newNativeAssetPayment($toAccountId, $amount, $this->accountId); + + return $this->sendPayment($payment, $signingKeys); + } + + /** + * @param Payment $payment + * @param $signingKeys + * @return HorizonResponse + * @throws \ErrorException + */ + public function sendPayment(Payment $payment, $signingKeys) + { + if ($payment->isNativeAsset()) { + $paymentOp = PaymentOp::newNativePayment($payment->getDestinationAccountId(), $payment->getAmount()->getBalanceAsStroops()); + } + else { + throw new \ErrorException('Not implemented'); + } + + $transaction = (new TransactionBuilder($this->accountId)) + ->setApiClient($this->apiClient) + ->addOperation( + $paymentOp + ) + ; + + return $transaction->submit($signingKeys); + } + + /** + * @param null $sinceCursor + * @param int $limit + * @return Transaction[] + */ + public function getTransactions($sinceCursor = null, $limit = 50) + { + $transactions = []; + + $url = sprintf('/accounts/%s/transactions', $this->accountId); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + if ($limit) $params['limit'] = $limit; + + if ($params) { + $url .= '?' . http_build_query($params); + } + + $response = $this->apiClient->get($url); + $rawTransactions = $response->getRecords(); + + foreach ($rawTransactions as $rawTransaction) { + $transaction = Transaction::fromRawResponseData($rawTransaction); + $transaction->setApiClient($this->getApiClient()); + + $transactions[] = $transaction; + } + + return $transactions; + } + + /** + * @param null $sinceCursor + * @param int $limit + * @return array + * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException + */ + public function getEffects($sinceCursor = null, $limit = 50) + { + $effects = []; + $url = sprintf('/accounts/%s/effects', $this->accountId); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + if ($limit) $params['limit'] = $limit; + + if ($params) { + $url .= '?' . http_build_query($params); + } + + $response = $this->apiClient->get($url); + $raw = $response->getRecords(); + + foreach ($raw as $rawEffect) { + $effect = Effect::fromRawResponseData($rawEffect); + $effect->setApiClient($this->getApiClient()); + + $effects[] = $effect; + } + + return $effects; + } + /** - * @param null $sinceCursor - * @param int $limit - * @return array - * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException - */ - public function getEffects($sinceCursor = null, $limit = 50) - { - $effects = []; - $url = sprintf('/accounts/%s/effects', $this->accountId); - $params = []; - - if ($sinceCursor) $params['cursor'] = $sinceCursor; - if ($limit) $params['limit'] = $limit; - - if ($params) { - $url .= '?' . http_build_query($params); - } - - $response = $this->apiClient->get($url); - $raw = $response->getRecords(); - - foreach ($raw as $rawEffect) { - $effect = Effect::fromRawResponseData($rawEffect); - $effect->setApiClient($this->getApiClient()); - - $effects[] = $effect; - } - - return $effects; - } - - /** - * @param null $sinceCursor - * @param int $limit - * @return array|AssetTransferInterface[]|RestApiModel[] + * Returns a heterogeneous list of payment-related records for this account + * as returned by Horizon's `/accounts/{id}/payments` endpoint. + * + * Includes multiple operation types present in that feed: + * - create_account + * - payment + * - account_merge + * - path_payment + * + * If you only need payment-like operations (and want to ignore account creation/merge + * records), call {@see Account::getPaymentOperations()} instead. + * + * @param null $sinceCursor Cursor from which to start. + * @param int $limit Max records to fetch. + * @return array|AssetTransferInterface[]|RestApiModel[] Typed model instances per record type. */ public function getPayments($sinceCursor = null, $limit = 50) { $results = []; - - $url = sprintf('/accounts/%s/payments', $this->accountId); - $params = []; - - if ($sinceCursor) $params['cursor'] = $sinceCursor; - if ($limit) $params['limit'] = $limit; - - if ($params) { - $url .= '?' . http_build_query($params); - } - - $response = $this->apiClient->get($url); - $rawRecords = $response->getRecords($limit); - + + $url = sprintf('/accounts/%s/payments', $this->accountId); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + if ($limit) $params['limit'] = $limit; + + if ($params) { + $url .= '?' . http_build_query($params); + } + + $response = $this->apiClient->get($url); + $rawRecords = $response->getRecords($limit); + foreach ($rawRecords as $rawRecord) { switch ($rawRecord['type']) { case 'create_account': @@ -259,30 +279,81 @@ public function getPayments($sinceCursor = null, $limit = 50) $result = PathPayment::fromRawResponseData($rawRecord); break; } - - $result->setApiClient($this->getApiClient()); - - $results[] = $result; - } - + + $result->setApiClient($this->getApiClient()); + + $results[] = $result; + } + return $results; } /** - * See ApiClient::streamPayments + * Returns only payment-like operations for this account. + * + * Filters the Horizon `/accounts/{id}/payments` feed to include only: + * - payment + * - path_payment * - * @param null $sinceCursor - * @param callable $callback + * Excludes record types that may also appear in that feed: + * - create_account + * - account_merge + * + * To retrieve the full, unfiltered feed, call {@see Account::getPayments()}. + * + * @param null $sinceCursor Cursor from which to start. + * @param int $limit Max records to fetch. + * @return array|AssetTransferInterface[] */ - public function streamPayments($sinceCursor = 'now', callable $callback = null) + public function getPaymentOperations($sinceCursor = null, $limit = 50) { - $this->apiClient->streamPayments($sinceCursor, $callback); - } + $payments = []; + + $url = sprintf('/accounts/%s/payments', $this->accountId); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + if ($limit) $params['limit'] = $limit; + $query = $params ? ('?' . http_build_query($params)) : ''; + $response = $this->apiClient->get($url . $query); + $rawRecords = $response->getRecords($limit); + + foreach ($rawRecords as $rawRecord) { + if ($rawRecord['type'] === 'payment') { + $result = Payment::fromRawResponseData($rawRecord); + } + elseif ($rawRecord['type'] === 'path_payment') { + $result = PathPayment::fromRawResponseData($rawRecord); + } + else { + continue; + } + + $result->setApiClient($this->getApiClient()); + $payments[] = $result; + } + + return $payments; + } + + /** + * See ApiClient::streamPayments + * + * @param null $sinceCursor + * @param callable $callback + */ + public function streamPayments($sinceCursor = 'now', callable $callback = null) + { + $this->apiClient->streamPayments($sinceCursor, $callback); + } + /** - * Returns a string representing the native balance + * Returns the native balance formatted to 7 decimal places (Stellar precision). + * + * Example: "12.3456789". If no native balance is present, returns "0.0000000". * - * @return string + * @return string 7-decimal string suitable for display * @throws \ErrorException */ public function getNativeBalance() @@ -293,131 +364,132 @@ public function getNativeBalance() if ($balance->isNativeAsset()) return $balance->getBalance(); } - return 0; + // Always return 7-decimal precision for display consistency + return '0.0000000'; } - + /** - * Returns the balance in stroops + * Returns the native balance in stroops (integer string, no decimals). * - * @return string + * @return string Integer string of stroops * @throws \ErrorException */ public function getNativeBalanceStroops() - { - MathSafety::require64Bit(); - - foreach ($this->getBalances() as $balance) { - if ($balance->isNativeAsset()) return $balance->getUnscaledBalance(); - } - - return "0"; - } - + { + MathSafety::require64Bit(); + + foreach ($this->getBalances() as $balance) { + if ($balance->isNativeAsset()) return $balance->getUnscaledBalance(); + } + + return "0"; + } + /** - * Returns the numeric balance of the given asset + * Returns the balance of a custom asset formatted to 7 decimal places, or null if not present. * * @param Asset $asset - * @return null|string + * @return null|string 7-decimal string or null if asset not found */ public function getCustomAssetBalanceValue(Asset $asset) - { - foreach ($this->getBalances() as $balance) { - if ($balance->getAssetCode() !== $asset->getAssetCode()) continue; - if ($balance->getAssetIssuerAccountId() != $asset->getIssuer()->getAccountIdString()) continue; - - return $balance->getBalance(); - } - - return null; - } - + { + foreach ($this->getBalances() as $balance) { + if ($balance->getAssetCode() !== $asset->getAssetCode()) continue; + if ($balance->getAssetIssuerAccountId() != $asset->getIssuer()->getAccountIdString()) continue; + + return $balance->getBalance(); + } + + return null; + } + + /** + * Returns an AssetAmount representing the balance of this asset + * + * @param Asset $asset + * @return null|AssetAmount + */ + public function getCustomAssetBalance(Asset $asset) + { + foreach ($this->getBalances() as $balance) { + if ($balance->getAssetCode() !== $asset->getAssetCode()) continue; + if ($balance->getAssetIssuerAccountId() != $asset->getIssuer()->getAccountIdString()) continue; + + return $balance; + } + + return null; + } + /** - * Returns an AssetAmount representing the balance of this asset + * Returns the balance of a custom asset in stroops (integer string), or null if not present. * * @param Asset $asset - * @return null|AssetAmount - */ - public function getCustomAssetBalance(Asset $asset) - { - foreach ($this->getBalances() as $balance) { - if ($balance->getAssetCode() !== $asset->getAssetCode()) continue; - if ($balance->getAssetIssuerAccountId() != $asset->getIssuer()->getAccountIdString()) continue; - - return $balance; - } - - return null; - } - - /** - * Returns the balance of a custom asset in stroops - * - * @param Asset $asset - * @return null|string + * @return null|string Integer string of stroops * @throws \ErrorException */ public function getCustomAssetBalanceStroops(Asset $asset) - { - MathSafety::require64Bit(); - - foreach ($this->getBalances() as $balance) { - if ($balance->getAssetCode() !== $asset->getAssetCode()) continue; - if ($balance->getAssetIssuerAccountId() != $asset->getIssuer()->getAccountIdString()) continue; - - return $balance->getUnscaledBalance(); - } - - return null; - } - - /** - * Returns an array holding account thresholds. - * - * @return array - */ - public function getThresholds() - { - return $this->thresholds; - } - - /** - * This returns the sequence exactly as it comes back from the Horizon API - * - * See getSequenceAsBigInteger if you need to use this value in a transaction - * or other 64-bit safe location. - * - * @return string - */ - public function getSequence() - { - return $this->sequence; - } - - /** - * @return BigInteger - */ - public function getSequenceAsBigInteger() - { - return new BigInteger($this->sequence); - } - - /** - * @return array|AssetAmount[] - */ - public function getBalances() - { - return $this->balances; - } - - /** - * Returns an array of key => value pairs - * - * Note that the values have been base64-decoded and may be binary data - * - * @return array - */ - public function getData() - { - return $this->data; - } -} \ No newline at end of file + { + MathSafety::require64Bit(); + + foreach ($this->getBalances() as $balance) { + if ($balance->getAssetCode() !== $asset->getAssetCode()) continue; + if ($balance->getAssetIssuerAccountId() != $asset->getIssuer()->getAccountIdString()) continue; + + return $balance->getUnscaledBalance(); + } + + return null; + } + + /** + * Returns an array holding account thresholds. + * + * @return array + */ + public function getThresholds() + { + return $this->thresholds; + } + + /** + * This returns the sequence exactly as it comes back from the Horizon API + * + * See getSequenceAsBigInteger if you need to use this value in a transaction + * or other 64-bit safe location. + * + * @return string + */ + public function getSequence() + { + return $this->sequence; + } + + /** + * @return BigInteger + */ + public function getSequenceAsBigInteger() + { + return new BigInteger($this->sequence); + } + + /** + * @return array|AssetAmount[] + */ + public function getBalances() + { + return $this->balances; + } + + /** + * Returns an array of key => value pairs + * + * Note that the values have been base64-decoded and may be binary data + * + * @return array + */ + public function getData() + { + return $this->data; + } +} diff --git a/src/Model/AccountMergeOperation.php b/src/Model/AccountMergeOperation.php index 7bc516a..3da0614 100644 --- a/src/Model/AccountMergeOperation.php +++ b/src/Model/AccountMergeOperation.php @@ -1,110 +1,110 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $id - * @param $type - */ - public function __construct($id, $type) - { - parent::__construct($id, Operation::TYPE_ACCOUNT_MERGE); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->sourceAccountId = $rawData['account']; - $this->mergeIntoAccountId = $rawData['into']; - } - - public function getAssetTransferType() - { - return $this->type; - } - - public function getFromAccountId() - { - return $this->sourceAccountId; - } - - public function getToAccountId() - { - return $this->mergeIntoAccountId; - } - - public function getAssetAmount() - { - return null; - } - - /** - * @return string - */ - public function getSourceAccountId() - { - return $this->sourceAccountId; - } - - /** - * @param string $sourceAccountId - */ - public function setSourceAccountId($sourceAccountId) - { - $this->sourceAccountId = $sourceAccountId; - } - - /** - * @return string - */ - public function getMergeIntoAccountId() - { - return $this->mergeIntoAccountId; - } - - /** - * @param string $mergeIntoAccountId - */ - public function setMergeIntoAccountId($mergeIntoAccountId) - { - $this->mergeIntoAccountId = $mergeIntoAccountId; - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $id + * @param $type + */ + public function __construct($id, $type) + { + parent::__construct($id, Operation::TYPE_ACCOUNT_MERGE); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->sourceAccountId = $rawData['account']; + $this->mergeIntoAccountId = $rawData['into']; + } + + public function getAssetTransferType() + { + return $this->type; + } + + public function getFromAccountId() + { + return $this->sourceAccountId; + } + + public function getToAccountId() + { + return $this->mergeIntoAccountId; + } + + public function getAssetAmount() + { + return null; + } + + /** + * @return string + */ + public function getSourceAccountId() + { + return $this->sourceAccountId; + } + + /** + * @param string $sourceAccountId + */ + public function setSourceAccountId($sourceAccountId) + { + $this->sourceAccountId = $sourceAccountId; + } + + /** + * @return string + */ + public function getMergeIntoAccountId() + { + return $this->mergeIntoAccountId; + } + + /** + * @param string $mergeIntoAccountId + */ + public function setMergeIntoAccountId($mergeIntoAccountId) + { + $this->mergeIntoAccountId = $mergeIntoAccountId; + } } \ No newline at end of file diff --git a/src/Model/AllowTrustOperation.php b/src/Model/AllowTrustOperation.php index 40b6132..3f29422 100644 --- a/src/Model/AllowTrustOperation.php +++ b/src/Model/AllowTrustOperation.php @@ -1,142 +1,142 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $id - * @param $type - */ - public function __construct($id, $type) - { - parent::__construct($id, Operation::TYPE_ALLOW_TRUST); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->trusteeAccountId = $rawData['trustee']; - $this->trustorAccountId = $rawData['trustor']; - $this->isAuthorized = $rawData['authorize']; - - $this->asset = new AssetAmount($rawData['limit'], $rawData['asset_type']); - $this->asset->setAssetIssuerAccountId($rawData['asset_issuer']); - $this->asset->setAssetCode($rawData['asset_code']); - } - - /** - * @return AssetAmount - */ - public function getAsset() - { - return $this->asset; - } - - /** - * @param AssetAmount $asset - */ - public function setAsset($asset) - { - $this->asset = $asset; - } - - /** - * @return string - */ - public function getTrusteeAccountId() - { - return $this->trusteeAccountId; - } - - /** - * @param string $trusteeAccountId - */ - public function setTrusteeAccountId($trusteeAccountId) - { - $this->trusteeAccountId = $trusteeAccountId; - } - - /** - * @return string - */ - public function getTrustorAccountId() - { - return $this->trustorAccountId; - } - - /** - * @param string $trustorAccountId - */ - public function setTrustorAccountId($trustorAccountId) - { - $this->trustorAccountId = $trustorAccountId; - } - - /** - * @return bool - */ - public function isAuthorized() - { - return $this->isAuthorized; - } - - /** - * @param bool $isAuthorized - */ - public function setIsAuthorized($isAuthorized) - { - $this->isAuthorized = $isAuthorized; - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $id + * @param $type + */ + public function __construct($id, $type) + { + parent::__construct($id, Operation::TYPE_ALLOW_TRUST); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->trusteeAccountId = $rawData['trustee']; + $this->trustorAccountId = $rawData['trustor']; + $this->isAuthorized = $rawData['authorize']; + + $this->asset = new AssetAmount($rawData['limit'], $rawData['asset_type']); + $this->asset->setAssetIssuerAccountId($rawData['asset_issuer']); + $this->asset->setAssetCode($rawData['asset_code']); + } + + /** + * @return AssetAmount + */ + public function getAsset() + { + return $this->asset; + } + + /** + * @param AssetAmount $asset + */ + public function setAsset($asset) + { + $this->asset = $asset; + } + + /** + * @return string + */ + public function getTrusteeAccountId() + { + return $this->trusteeAccountId; + } + + /** + * @param string $trusteeAccountId + */ + public function setTrusteeAccountId($trusteeAccountId) + { + $this->trusteeAccountId = $trusteeAccountId; + } + + /** + * @return string + */ + public function getTrustorAccountId() + { + return $this->trustorAccountId; + } + + /** + * @param string $trustorAccountId + */ + public function setTrustorAccountId($trustorAccountId) + { + $this->trustorAccountId = $trustorAccountId; + } + + /** + * @return bool + */ + public function isAuthorized() + { + return $this->isAuthorized; + } + + /** + * @param bool $isAuthorized + */ + public function setIsAuthorized($isAuthorized) + { + $this->isAuthorized = $isAuthorized; + } } \ No newline at end of file diff --git a/src/Model/AssetAmount.php b/src/Model/AssetAmount.php index d4b944c..a6aa15c 100755 --- a/src/Model/AssetAmount.php +++ b/src/Model/AssetAmount.php @@ -1,183 +1,187 @@ -assetType = $assetType; + + $this->amount = new StellarAmount($amount); + } + + public function __toString() + { + return sprintf("%s %s", strval($this->getBalance()), $this->getAssetCode()); + } + + /** + * @return bool + */ + public function isNativeAsset() + { + return self::ASSET_TYPE_NATIVE == $this->assetType; + } + + /** + * @return StellarAmount + */ + public function getLimit() + { + return $this->limit; + } + + /** + * @param number|BigInteger $limit + */ + public function setLimit($limit) + { + $this->limit = new StellarAmount($limit); + } + + /** + * @return string + */ + public function getAssetType() + { + return $this->assetType; + } + + public function getAssetCode() + { + if ($this->isNativeAsset()) return 'XLM'; + + return $this->assetCode; + } + + /** + * @param string $assetType + */ + public function setAssetType($assetType) + { + $this->assetType = $assetType; + } + + /** + * Returns the unscaled balance in stroops (integer string, no decimals). * - * This class stores the balance internally as a StellarAmount - * - * @param number|BigInteger $amount - * @param string $assetType - */ - public function __construct($amount, $assetType = 'native') - { - $this->assetType = $assetType; - - $this->amount = new StellarAmount($amount); - } - - public function __toString() - { - return sprintf("%s %s", strval($this->getBalance()), $this->getAssetCode()); - } - - /** - * @return bool - */ - public function isNativeAsset() - { - return self::ASSET_TYPE_NATIVE == $this->assetType; - } - - /** - * @return StellarAmount - */ - public function getLimit() - { - return $this->limit; - } - - /** - * @param number|BigInteger $limit - */ - public function setLimit($limit) - { - $this->limit = new StellarAmount($limit); - } - - /** - * @return string - */ - public function getAssetType() - { - return $this->assetType; - } - - public function getAssetCode() - { - if ($this->isNativeAsset()) return 'XLM'; - - return $this->assetCode; - } - - /** - * @param string $assetType - */ - public function setAssetType($assetType) - { - $this->assetType = $assetType; - } - - /** - * @return string + * @return string Integer string of stroops */ public function getUnscaledBalance() - { - return $this->amount->getUnscaledString(); - } - + { + return $this->amount->getUnscaledString(); + } + /** - * @return number + * Returns the balance formatted to 7 decimal places (Stellar precision). + * + * @return string 7-decimal string suitable for display */ public function getBalance() { return $this->amount->getScaledValue(); } - - /** - * Returns the stroop representation of this AssetAmount - * - * @return BigInteger - */ - public function getBalanceAsStroops() - { - return $this->amount->getUnscaledBigInteger(); - } - - /** - * @param number|BigInteger $amount - */ - public function setAmount($amount) - { - $this->amount = new StellarAmount($amount); - } - - /** - * @return string - */ - public function getAssetIssuerAccountId() - { - return $this->assetIssuerAccountId; - } - - /** - * @param string $assetIssuerAccountId - */ - public function setAssetIssuerAccountId($assetIssuerAccountId) - { - $this->assetIssuerAccountId = $assetIssuerAccountId; - } - - /** - * @param string $assetCode - */ - public function setAssetCode($assetCode) - { - $this->assetCode = $assetCode; - } -} \ No newline at end of file + + /** + * Returns the stroop representation of this AssetAmount + * + * @return BigInteger + */ + public function getBalanceAsStroops() + { + return $this->amount->getUnscaledBigInteger(); + } + + /** + * @param number|BigInteger $amount + */ + public function setAmount($amount) + { + $this->amount = new StellarAmount($amount); + } + + /** + * @return string + */ + public function getAssetIssuerAccountId() + { + return $this->assetIssuerAccountId; + } + + /** + * @param string $assetIssuerAccountId + */ + public function setAssetIssuerAccountId($assetIssuerAccountId) + { + $this->assetIssuerAccountId = $assetIssuerAccountId; + } + + /** + * @param string $assetCode + */ + public function setAssetCode($assetCode) + { + $this->assetCode = $assetCode; + } +} diff --git a/src/Model/AssetTransferInterface.php b/src/Model/AssetTransferInterface.php index b79bc12..c34a2ac 100644 --- a/src/Model/AssetTransferInterface.php +++ b/src/Model/AssetTransferInterface.php @@ -1,37 +1,37 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $id - * @param $type - */ - public function __construct($id, $type) - { - parent::__construct($id, Operation::TYPE_BUMP_SEQUENCE); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->bumpTo = new BigInteger($rawData['bump_to']); - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $id + * @param $type + */ + public function __construct($id, $type) + { + parent::__construct($id, Operation::TYPE_BUMP_SEQUENCE); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->bumpTo = new BigInteger($rawData['bump_to']); + } } \ No newline at end of file diff --git a/src/Model/ChangeTrustOperation.php b/src/Model/ChangeTrustOperation.php index a3ad917..de5b05d 100644 --- a/src/Model/ChangeTrustOperation.php +++ b/src/Model/ChangeTrustOperation.php @@ -1,118 +1,118 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $id - * @param $type - */ - public function __construct($id, $type) - { - parent::__construct($id, Operation::TYPE_CHANGE_TRUST); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->trusteeAccountId = $rawData['trustee']; - $this->trustorAccountId = $rawData['trustor']; - - $this->asset = new AssetAmount($rawData['limit'], $rawData['asset_type']); - $this->asset->setAssetIssuerAccountId($rawData['asset_issuer']); - $this->asset->setAssetCode($rawData['asset_code']); - } - - /** - * @return AssetAmount - */ - public function getAsset() - { - return $this->asset; - } - - /** - * @param AssetAmount $asset - */ - public function setAsset($asset) - { - $this->asset = $asset; - } - - /** - * @return string - */ - public function getTrusteeAccountId() - { - return $this->trusteeAccountId; - } - - /** - * @param string $trusteeAccountId - */ - public function setTrusteeAccountId($trusteeAccountId) - { - $this->trusteeAccountId = $trusteeAccountId; - } - - /** - * @return string - */ - public function getTrustorAccountId() - { - return $this->trustorAccountId; - } - - /** - * @param string $trustorAccountId - */ - public function setTrustorAccountId($trustorAccountId) - { - $this->trustorAccountId = $trustorAccountId; - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $id + * @param $type + */ + public function __construct($id, $type) + { + parent::__construct($id, Operation::TYPE_CHANGE_TRUST); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->trusteeAccountId = $rawData['trustee']; + $this->trustorAccountId = $rawData['trustor']; + + $this->asset = new AssetAmount($rawData['limit'], $rawData['asset_type']); + $this->asset->setAssetIssuerAccountId($rawData['asset_issuer']); + $this->asset->setAssetCode($rawData['asset_code']); + } + + /** + * @return AssetAmount + */ + public function getAsset() + { + return $this->asset; + } + + /** + * @param AssetAmount $asset + */ + public function setAsset($asset) + { + $this->asset = $asset; + } + + /** + * @return string + */ + public function getTrusteeAccountId() + { + return $this->trusteeAccountId; + } + + /** + * @param string $trusteeAccountId + */ + public function setTrusteeAccountId($trusteeAccountId) + { + $this->trusteeAccountId = $trusteeAccountId; + } + + /** + * @return string + */ + public function getTrustorAccountId() + { + return $this->trustorAccountId; + } + + /** + * @param string $trustorAccountId + */ + public function setTrustorAccountId($trustorAccountId) + { + $this->trustorAccountId = $trustorAccountId; + } } \ No newline at end of file diff --git a/src/Model/CreateAccountOperation.php b/src/Model/CreateAccountOperation.php index 0c6b9be..36aee0b 100644 --- a/src/Model/CreateAccountOperation.php +++ b/src/Model/CreateAccountOperation.php @@ -1,126 +1,126 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - public function __construct($id, $type) - { - parent::__construct($id, Operation::TYPE_CREATE_ACCOUNT); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->newAccountId = $rawData['account']; - $this->fundingAccountId = $rawData['funder']; - - $this->startingBalance = new AssetAmount($rawData['starting_balance']); - } - - public function getAssetTransferType() - { - return $this->type; - } - - public function getFromAccountId() - { - return $this->fundingAccountId; - } - - public function getToAccountId() - { - return $this->newAccountId; - } - - public function getAssetAmount() - { - return $this->startingBalance; - } - - /** - * @return string - */ - public function getNewAccountId() - { - return $this->newAccountId; - } - - /** - * @param string $newAccountId - */ - public function setNewAccountId($newAccountId) - { - $this->newAccountId = $newAccountId; - } - - /** - * @return string - */ - public function getFundingAccountId() - { - return $this->fundingAccountId; - } - - /** - * @param string $fundingAccountId - */ - public function setFundingAccountId($fundingAccountId) - { - $this->fundingAccountId = $fundingAccountId; - } - - /** - * @return AssetAmount - */ - public function getStartingBalance() - { - return $this->startingBalance; - } - - /** - * @param AssetAmount $startingBalance - */ - public function setStartingBalance($startingBalance) - { - $this->startingBalance = $startingBalance; - } +loadFromRawResponseData($rawData); + + return $object; + } + + public function __construct($id, $type) + { + parent::__construct($id, Operation::TYPE_CREATE_ACCOUNT); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->newAccountId = $rawData['account']; + $this->fundingAccountId = $rawData['funder']; + + $this->startingBalance = new AssetAmount($rawData['starting_balance']); + } + + public function getAssetTransferType() + { + return $this->type; + } + + public function getFromAccountId() + { + return $this->fundingAccountId; + } + + public function getToAccountId() + { + return $this->newAccountId; + } + + public function getAssetAmount() + { + return $this->startingBalance; + } + + /** + * @return string + */ + public function getNewAccountId() + { + return $this->newAccountId; + } + + /** + * @param string $newAccountId + */ + public function setNewAccountId($newAccountId) + { + $this->newAccountId = $newAccountId; + } + + /** + * @return string + */ + public function getFundingAccountId() + { + return $this->fundingAccountId; + } + + /** + * @param string $fundingAccountId + */ + public function setFundingAccountId($fundingAccountId) + { + $this->fundingAccountId = $fundingAccountId; + } + + /** + * @return AssetAmount + */ + public function getStartingBalance() + { + return $this->startingBalance; + } + + /** + * @param AssetAmount $startingBalance + */ + public function setStartingBalance($startingBalance) + { + $this->startingBalance = $startingBalance; + } } \ No newline at end of file diff --git a/src/Model/CreatePassiveOfferOperation.php b/src/Model/CreatePassiveOfferOperation.php index 3c79eb5..0184383 100644 --- a/src/Model/CreatePassiveOfferOperation.php +++ b/src/Model/CreatePassiveOfferOperation.php @@ -1,20 +1,20 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * Operation type - * - * @param $type - */ - public function __construct($type) - { - $this->type = $type; - - $this->extraData = []; - } - - public function __toString() - { - return sprintf('%s:%s', $this->type, $this->id); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - // The fields in the Effect response differ slightly from those available - // in the Operation, so known fields are stored in this class and everything - // else goes in extraData - $knownFields = ['_links', 'id', 'type', 'type_i']; - - if (isset($rawData['type'])) $this->type = $rawData['type']; - if (isset($rawData['type_i'])) $this->typeI = $rawData['type_i']; - - foreach ($rawData as $key => $value) { - if (in_array($key, $knownFields)) continue; - - $this->extraData[$key] = $value; - } - } - - /** - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * @param string $type - */ - public function setType($type) - { - $this->type = $type; - } - - /** - * @return int - */ - public function getTypeI() - { - return $this->typeI; - } - - /** - * @param int $typeI - */ - public function setTypeI($typeI) - { - $this->typeI = $typeI; - } - - /** - * @return Operation - */ - public function getOperation() - { - return $this->operation; - } - - /** - * @param Operation $operation - */ - public function setOperation(Operation $operation) - { - $this->operation = $operation; - } - - /** - * @return array - */ - public function getExtraData() - { - return $this->extraData; - } - - /** - * @param array $extraData - */ - public function setExtraData($extraData) - { - $this->extraData = $extraData; - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * Operation type + * + * @param $type + */ + public function __construct($type) + { + $this->type = $type; + + $this->extraData = []; + } + + public function __toString() + { + return sprintf('%s:%s', $this->type, $this->id); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + // The fields in the Effect response differ slightly from those available + // in the Operation, so known fields are stored in this class and everything + // else goes in extraData + $knownFields = ['_links', 'id', 'type', 'type_i']; + + if (isset($rawData['type'])) $this->type = $rawData['type']; + if (isset($rawData['type_i'])) $this->typeI = $rawData['type_i']; + + foreach ($rawData as $key => $value) { + if (in_array($key, $knownFields)) continue; + + $this->extraData[$key] = $value; + } + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @param string $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * @return int + */ + public function getTypeI() + { + return $this->typeI; + } + + /** + * @param int $typeI + */ + public function setTypeI($typeI) + { + $this->typeI = $typeI; + } + + /** + * @return Operation + */ + public function getOperation() + { + return $this->operation; + } + + /** + * @param Operation $operation + */ + public function setOperation(Operation $operation) + { + $this->operation = $operation; + } + + /** + * @return array + */ + public function getExtraData() + { + return $this->extraData; + } + + /** + * @param array $extraData + */ + public function setExtraData($extraData) + { + $this->extraData = $extraData; + } } \ No newline at end of file diff --git a/src/Model/InflationOperation.php b/src/Model/InflationOperation.php index 4a9d4fd..18a9673 100644 --- a/src/Model/InflationOperation.php +++ b/src/Model/InflationOperation.php @@ -1,33 +1,33 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $id - * @param $type - */ - public function __construct($id, $type) - { - parent::__construct($id, Operation::TYPE_INFLATION); - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $id + * @param $type + */ + public function __construct($id, $type) + { + parent::__construct($id, Operation::TYPE_INFLATION); + } } \ No newline at end of file diff --git a/src/Model/Ledger.php b/src/Model/Ledger.php index 21c0ad4..4bce5ca 100644 --- a/src/Model/Ledger.php +++ b/src/Model/Ledger.php @@ -1,316 +1,316 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - if (isset($rawData['hash'])) $this->hash = $rawData['hash']; - if (isset($rawData['prev_hash'])) $this->previousHash = $rawData['prev_hash']; - if (isset($rawData['sequence'])) $this->sequence = strval($rawData['sequence']); - if (isset($rawData['transaction_count'])) $this->transactionCount = $rawData['transaction_count']; - if (isset($rawData['operation_count'])) $this->operationCount = $rawData['operation_count']; - if (isset($rawData['closed_at'])) $this->closedAt = \DateTime::createFromFormat(DATE_ISO8601, $rawData['closed_at']); - if (isset($rawData['total_coins'])) $this->totalCoins = strval($rawData['total_coins']); - if (isset($rawData['fee_pool'])) $this->feePool = $rawData['fee_pool']; - if (isset($rawData['base_fee'])) $this->baseFee = $rawData['base_fee']; - if (isset($rawData['base_reserve'])) $this->baseReserve = $rawData['base_reserve']; - if (isset($rawData['max_tx_set_size'])) $this->maxTransactionSetSize = $rawData['max_tx_set_size']; - if (isset($rawData['protocol_version'])) $this->protocolVersion = $rawData['protocol_version']; - } - - /** - * @return string - */ - public function getHash() - { - return $this->hash; - } - - /** - * @param string $hash - */ - public function setHash($hash) - { - $this->hash = $hash; - } - - /** - * @return string - */ - public function getPreviousHash() - { - return $this->previousHash; - } - - /** - * @param string $previousHash - */ - public function setPreviousHash($previousHash) - { - $this->previousHash = $previousHash; - } - - /** - * @return string - */ - public function getSequence() - { - return $this->sequence; - } - - /** - * @param string $sequence - */ - public function setSequence($sequence) - { - $this->sequence = $sequence; - } - - /** - * @return int - */ - public function getTransactionCount() - { - return $this->transactionCount; - } - - /** - * @param int $transactionCount - */ - public function setTransactionCount($transactionCount) - { - $this->transactionCount = $transactionCount; - } - - /** - * @return int - */ - public function getOperationCount() - { - return $this->operationCount; - } - - /** - * @param int $operationCount - */ - public function setOperationCount($operationCount) - { - $this->operationCount = $operationCount; - } - - /** - * @return \DateTime - */ - public function getClosedAt() - { - return $this->closedAt; - } - - /** - * @param \DateTime $closedAt - */ - public function setClosedAt($closedAt) - { - $this->closedAt = $closedAt; - } - - /** - * @return string - */ - public function getTotalCoins() - { - return $this->totalCoins; - } - - /** - * @param string $totalCoins - */ - public function setTotalCoins($totalCoins) - { - $this->totalCoins = $totalCoins; - } - - /** - * @return string - */ - public function getFeePool() - { - return $this->feePool; - } - - /** - * @param string $feePool - */ - public function setFeePool($feePool) - { - $this->feePool = $feePool; - } - - /** - * @return int - */ - public function getBaseFee() - { - return $this->baseFee; - } - - /** - * @param int $baseFee - */ - public function setBaseFee($baseFee) - { - $this->baseFee = $baseFee; - } - - /** - * @return string - */ - public function getBaseReserve() - { - return $this->baseReserve; - } - - /** - * @param string $baseReserve - */ - public function setBaseReserve($baseReserve) - { - $this->baseReserve = $baseReserve; - } - - /** - * @return int - */ - public function getMaxTransactionSetSize() - { - return $this->maxTransactionSetSize; - } - - /** - * @param int $maxTransactionSetSize - */ - public function setMaxTransactionSetSize($maxTransactionSetSize) - { - $this->maxTransactionSetSize = $maxTransactionSetSize; - } - - /** - * @return int - */ - public function getProtocolVersion() - { - return $this->protocolVersion; - } - - /** - * @param int $protocolVersion - */ - public function setProtocolVersion($protocolVersion) - { - $this->protocolVersion = $protocolVersion; - } +loadFromRawResponseData($rawData); + + return $object; + } + + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + if (isset($rawData['hash'])) $this->hash = $rawData['hash']; + if (isset($rawData['prev_hash'])) $this->previousHash = $rawData['prev_hash']; + if (isset($rawData['sequence'])) $this->sequence = strval($rawData['sequence']); + if (isset($rawData['transaction_count'])) $this->transactionCount = $rawData['transaction_count']; + if (isset($rawData['operation_count'])) $this->operationCount = $rawData['operation_count']; + if (isset($rawData['closed_at'])) $this->closedAt = \DateTime::createFromFormat(DATE_ISO8601, $rawData['closed_at']); + if (isset($rawData['total_coins'])) $this->totalCoins = strval($rawData['total_coins']); + if (isset($rawData['fee_pool'])) $this->feePool = $rawData['fee_pool']; + if (isset($rawData['base_fee'])) $this->baseFee = $rawData['base_fee']; + if (isset($rawData['base_reserve'])) $this->baseReserve = $rawData['base_reserve']; + if (isset($rawData['max_tx_set_size'])) $this->maxTransactionSetSize = $rawData['max_tx_set_size']; + if (isset($rawData['protocol_version'])) $this->protocolVersion = $rawData['protocol_version']; + } + + /** + * @return string + */ + public function getHash() + { + return $this->hash; + } + + /** + * @param string $hash + */ + public function setHash($hash) + { + $this->hash = $hash; + } + + /** + * @return string + */ + public function getPreviousHash() + { + return $this->previousHash; + } + + /** + * @param string $previousHash + */ + public function setPreviousHash($previousHash) + { + $this->previousHash = $previousHash; + } + + /** + * @return string + */ + public function getSequence() + { + return $this->sequence; + } + + /** + * @param string $sequence + */ + public function setSequence($sequence) + { + $this->sequence = $sequence; + } + + /** + * @return int + */ + public function getTransactionCount() + { + return $this->transactionCount; + } + + /** + * @param int $transactionCount + */ + public function setTransactionCount($transactionCount) + { + $this->transactionCount = $transactionCount; + } + + /** + * @return int + */ + public function getOperationCount() + { + return $this->operationCount; + } + + /** + * @param int $operationCount + */ + public function setOperationCount($operationCount) + { + $this->operationCount = $operationCount; + } + + /** + * @return \DateTime + */ + public function getClosedAt() + { + return $this->closedAt; + } + + /** + * @param \DateTime $closedAt + */ + public function setClosedAt($closedAt) + { + $this->closedAt = $closedAt; + } + + /** + * @return string + */ + public function getTotalCoins() + { + return $this->totalCoins; + } + + /** + * @param string $totalCoins + */ + public function setTotalCoins($totalCoins) + { + $this->totalCoins = $totalCoins; + } + + /** + * @return string + */ + public function getFeePool() + { + return $this->feePool; + } + + /** + * @param string $feePool + */ + public function setFeePool($feePool) + { + $this->feePool = $feePool; + } + + /** + * @return int + */ + public function getBaseFee() + { + return $this->baseFee; + } + + /** + * @param int $baseFee + */ + public function setBaseFee($baseFee) + { + $this->baseFee = $baseFee; + } + + /** + * @return string + */ + public function getBaseReserve() + { + return $this->baseReserve; + } + + /** + * @param string $baseReserve + */ + public function setBaseReserve($baseReserve) + { + $this->baseReserve = $baseReserve; + } + + /** + * @return int + */ + public function getMaxTransactionSetSize() + { + return $this->maxTransactionSetSize; + } + + /** + * @param int $maxTransactionSetSize + */ + public function setMaxTransactionSetSize($maxTransactionSetSize) + { + $this->maxTransactionSetSize = $maxTransactionSetSize; + } + + /** + * @return int + */ + public function getProtocolVersion() + { + return $this->protocolVersion; + } + + /** + * @param int $protocolVersion + */ + public function setProtocolVersion($protocolVersion) + { + $this->protocolVersion = $protocolVersion; + } } \ No newline at end of file diff --git a/src/Model/ManageDataOperation.php b/src/Model/ManageDataOperation.php index 7d35570..cbeac50 100644 --- a/src/Model/ManageDataOperation.php +++ b/src/Model/ManageDataOperation.php @@ -1,110 +1,110 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $id - * @param $type - */ - public function __construct($id, $type) - { - parent::__construct($id, Operation::TYPE_MANAGE_DATA); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->sourceAccountId = $rawData['source_account']; - $this->name = $rawData['name']; - $this->value = $rawData['value']; - } - - /** - * @return string - */ - public function getSourceAccountId() - { - return $this->sourceAccountId; - } - - /** - * @param string $sourceAccountId - */ - public function setSourceAccountId($sourceAccountId) - { - $this->sourceAccountId = $sourceAccountId; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @param string $name - */ - public function setName($name) - { - $this->name = $name; - } - - /** - * @return string - */ - public function getValue() - { - return $this->value; - } - - /** - * @param string $value - */ - public function setValue($value) - { - $this->value = $value; - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $id + * @param $type + */ + public function __construct($id, $type) + { + parent::__construct($id, Operation::TYPE_MANAGE_DATA); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->sourceAccountId = $rawData['source_account']; + $this->name = $rawData['name']; + $this->value = $rawData['value']; + } + + /** + * @return string + */ + public function getSourceAccountId() + { + return $this->sourceAccountId; + } + + /** + * @param string $sourceAccountId + */ + public function setSourceAccountId($sourceAccountId) + { + $this->sourceAccountId = $sourceAccountId; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $name + */ + public function setName($name) + { + $this->name = $name; + } + + /** + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * @param string $value + */ + public function setValue($value) + { + $this->value = $value; + } } \ No newline at end of file diff --git a/src/Model/ManageOfferOperation.php b/src/Model/ManageOfferOperation.php index 3146d3a..c3ede42 100644 --- a/src/Model/ManageOfferOperation.php +++ b/src/Model/ManageOfferOperation.php @@ -1,89 +1,89 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $id - * @param $type - */ - public function __construct($id, $type = Operation::TYPE_MANAGE_OFFER) - { - parent::__construct($id, $type); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->offerId = $rawData['offer_id']; - $this->price = $rawData['price']; - $this->priceR = $rawData['price_r']; - - // todo: verify that amount is shared between buying and selling? - if (isset($rawData['buying_asset_code'])) { - $this->buyingAsset = new AssetAmount($rawData['amount'], $rawData['buying_asset_code']); - $this->buyingAsset->setAssetIssuerAccountId($rawData['buying_asset_issuer']); - $this->buyingAsset->setAssetType($rawData['buying_asset_type']); - } - else if (isset($rawData['selling_asset_code'])) { - $this->sellingAsset = new AssetAmount($rawData['amount'], $rawData['selling_asset_code']); - $this->sellingAsset->setAssetIssuerAccountId($rawData['selling_asset_issuer']); - $this->sellingAsset->setAssetType($rawData['selling_asset_type']); - } - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $id + * @param $type + */ + public function __construct($id, $type = Operation::TYPE_MANAGE_OFFER) + { + parent::__construct($id, $type); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->offerId = $rawData['offer_id']; + $this->price = $rawData['price']; + $this->priceR = $rawData['price_r']; + + // todo: verify that amount is shared between buying and selling? + if (isset($rawData['buying_asset_code'])) { + $this->buyingAsset = new AssetAmount($rawData['amount'], $rawData['buying_asset_code']); + $this->buyingAsset->setAssetIssuerAccountId($rawData['buying_asset_issuer']); + $this->buyingAsset->setAssetType($rawData['buying_asset_type']); + } + else if (isset($rawData['selling_asset_code'])) { + $this->sellingAsset = new AssetAmount($rawData['amount'], $rawData['selling_asset_code']); + $this->sellingAsset->setAssetIssuerAccountId($rawData['selling_asset_issuer']); + $this->sellingAsset->setAssetType($rawData['selling_asset_type']); + } + } } \ No newline at end of file diff --git a/src/Model/Operation.php b/src/Model/Operation.php index 0b54907..2362458 100644 --- a/src/Model/Operation.php +++ b/src/Model/Operation.php @@ -1,186 +1,186 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * Operation constructor. - * - * @param $id - * @param $type - */ - public function __construct($id, $type) - { - $this->id = $id; - $this->type = $type; - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->id = $rawData['id']; - $this->type = $rawData['type']; - $this->typeI = $rawData['type_i']; - - if (isset($rawData['paging_token'])) $this->pagingToken = $rawData['paging_token']; - if (isset($rawData['transaction_hash'])) $this->transactionHash = $rawData['transaction_hash']; - } - - /** - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * @param string $id - */ - public function setId($id) - { - $this->id = $id; - } - - /** - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * @param string $type - */ - public function setType($type) - { - $this->type = $type; - } - - /** - * @return int - */ - public function getTypeI() - { - return $this->typeI; - } - - /** - * @param int $typeI - */ - public function setTypeI($typeI) - { - $this->typeI = $typeI; - } - - /** - * @return string - */ - public function getTransactionHash() - { - return $this->transactionHash; - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * Operation constructor. + * + * @param $id + * @param $type + */ + public function __construct($id, $type) + { + $this->id = $id; + $this->type = $type; + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->id = $rawData['id']; + $this->type = $rawData['type']; + $this->typeI = $rawData['type_i']; + + if (isset($rawData['paging_token'])) $this->pagingToken = $rawData['paging_token']; + if (isset($rawData['transaction_hash'])) $this->transactionHash = $rawData['transaction_hash']; + } + + /** + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * @param string $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * @param string $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * @return int + */ + public function getTypeI() + { + return $this->typeI; + } + + /** + * @param int $typeI + */ + public function setTypeI($typeI) + { + $this->typeI = $typeI; + } + + /** + * @return string + */ + public function getTransactionHash() + { + return $this->transactionHash; + } } \ No newline at end of file diff --git a/src/Model/PathPayment.php b/src/Model/PathPayment.php index 747bb14..d9b3142 100644 --- a/src/Model/PathPayment.php +++ b/src/Model/PathPayment.php @@ -1,169 +1,169 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - public function __construct($id, $type) - { - parent::__construct($id, Operation::TYPE_CREATE_ACCOUNT); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->fromAccountId = $rawData['from']; - $this->toAccountId = $rawData['to']; - - // Destination asset - $destinationAsset = new AssetAmount($rawData['amount'], $rawData['asset_type']); - $destinationAsset->setAssetIssuerAccountId($rawData['asset_issuer']); - $destinationAsset->setAssetCode($rawData['asset_code']); - $this->destinationAsset = $destinationAsset; - - // Source asset - $sourceAsset = new AssetAmount($rawData['source_amount'], $rawData['source_asset_type']); - $sourceAsset->setAssetIssuerAccountId($rawData['source_asset_issuer']); - $sourceAsset->setAssetCode($rawData['source_asset_code']); - $this->sourceAsset = $sourceAsset; - - // Max amount is the same as the source asset, but with a different amount - $sourceAssetMax = new AssetAmount($rawData['source_max'], $rawData['source_asset_type']); - $sourceAssetMax->setAssetIssuerAccountId($rawData['source_asset_issuer']); - $sourceAssetMax->setAssetCode($rawData['source_asset_code']); - $this->sourceMax = $sourceAssetMax; - } - - public function getAssetTransferType() - { - return $this->type; - } - - public function getAssetAmount() - { - return $this->destinationAsset; - } - /** - * @return string - */ - public function getFromAccountId() - { - return $this->fromAccountId; - } - - /** - * @param string $fromAccountId - */ - public function setFromAccountId($fromAccountId) - { - $this->fromAccountId = $fromAccountId; - } - - /** - * @return string - */ - public function getToAccountId() - { - return $this->toAccountId; - } - - /** - * @param string $toAccountId - */ - public function setToAccountId($toAccountId) - { - $this->toAccountId = $toAccountId; - } - - /** - * @return AssetAmount - */ - public function getDestinationAsset() - { - return $this->destinationAsset; - } - - /** - * @param AssetAmount $destinationAsset - */ - public function setDestinationAsset($destinationAsset) - { - $this->destinationAsset = $destinationAsset; - } - - /** - * @return AssetAmount - */ - public function getSourceAsset() - { - return $this->sourceAsset; - } - - /** - * @param AssetAmount $sourceAsset - */ - public function setSourceAsset($sourceAsset) - { - $this->sourceAsset = $sourceAsset; - } - - /** - * @return AssetAmount - */ - public function getSourceMax() - { - return $this->sourceMax; - } - - /** - * @param AssetAmount $sourceMax - */ - public function setSourceMax($sourceMax) - { - $this->sourceMax = $sourceMax; - } +loadFromRawResponseData($rawData); + + return $object; + } + + public function __construct($id, $type) + { + parent::__construct($id, Operation::TYPE_CREATE_ACCOUNT); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->fromAccountId = $rawData['from']; + $this->toAccountId = $rawData['to']; + + // Destination asset + $destinationAsset = new AssetAmount($rawData['amount'], $rawData['asset_type']); + $destinationAsset->setAssetIssuerAccountId($rawData['asset_issuer']); + $destinationAsset->setAssetCode($rawData['asset_code']); + $this->destinationAsset = $destinationAsset; + + // Source asset + $sourceAsset = new AssetAmount($rawData['source_amount'], $rawData['source_asset_type']); + $sourceAsset->setAssetIssuerAccountId($rawData['source_asset_issuer']); + $sourceAsset->setAssetCode($rawData['source_asset_code']); + $this->sourceAsset = $sourceAsset; + + // Max amount is the same as the source asset, but with a different amount + $sourceAssetMax = new AssetAmount($rawData['source_max'], $rawData['source_asset_type']); + $sourceAssetMax->setAssetIssuerAccountId($rawData['source_asset_issuer']); + $sourceAssetMax->setAssetCode($rawData['source_asset_code']); + $this->sourceMax = $sourceAssetMax; + } + + public function getAssetTransferType() + { + return $this->type; + } + + public function getAssetAmount() + { + return $this->destinationAsset; + } + /** + * @return string + */ + public function getFromAccountId() + { + return $this->fromAccountId; + } + + /** + * @param string $fromAccountId + */ + public function setFromAccountId($fromAccountId) + { + $this->fromAccountId = $fromAccountId; + } + + /** + * @return string + */ + public function getToAccountId() + { + return $this->toAccountId; + } + + /** + * @param string $toAccountId + */ + public function setToAccountId($toAccountId) + { + $this->toAccountId = $toAccountId; + } + + /** + * @return AssetAmount + */ + public function getDestinationAsset() + { + return $this->destinationAsset; + } + + /** + * @param AssetAmount $destinationAsset + */ + public function setDestinationAsset($destinationAsset) + { + $this->destinationAsset = $destinationAsset; + } + + /** + * @return AssetAmount + */ + public function getSourceAsset() + { + return $this->sourceAsset; + } + + /** + * @param AssetAmount $sourceAsset + */ + public function setSourceAsset($sourceAsset) + { + $this->sourceAsset = $sourceAsset; + } + + /** + * @return AssetAmount + */ + public function getSourceMax() + { + return $this->sourceMax; + } + + /** + * @param AssetAmount $sourceMax + */ + public function setSourceMax($sourceMax) + { + $this->sourceMax = $sourceMax; + } } \ No newline at end of file diff --git a/src/Model/Payment.php b/src/Model/Payment.php index d3e45d2..024801f 100755 --- a/src/Model/Payment.php +++ b/src/Model/Payment.php @@ -1,192 +1,192 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $toAccountId - * @param $amount - * @return Payment - */ - public static function newNativeAssetPayment($toAccountId, $amount, $fromAccountId, $sourceAccountId = null) - { - $payment = new Payment(null); - $payment->toAccountId = $toAccountId; - $payment->amount = new AssetAmount($amount); - $payment->fromAccountId = $fromAccountId; - - if ($sourceAccountId === null) $payment->sourceAccountId = $fromAccountId; - - return $payment; - } - - /** - * @param $id - * @param $type - */ - public function __construct($id) - { - parent::__construct($id, Operation::TYPE_PAYMENT); - - $this->amount = new AssetAmount('0'); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - $this->sourceAccountId = $rawData['source_account']; - - if (isset($rawData['from'])) $this->fromAccountId = $rawData['from']; - if (isset($rawData['to'])) $this->toAccountId = $rawData['to']; - - $assetAmount = null; - // Native assets - if ('native' == $rawData['asset_type']) { - $assetAmount = new AssetAmount($rawData['amount']); - } - // Custom assets - else { - $assetAmount = new AssetAmount($rawData['amount'], $rawData['asset_type']); - $assetAmount->setAssetIssuerAccountId($rawData['asset_issuer']); - $assetAmount->setAssetCode($rawData['asset_code']); - } - - $this->amount = $assetAmount; - } - - public function getAssetTransferType() - { - return $this->type; - } - - public function getAssetAmount() - { - return $this->amount; - } - - /** - * @return bool - */ - public function isNativeAsset() - { - return $this->amount->isNativeAsset(); - } - - /** - * @return mixed - */ - public function getSourceAccountId() - { - return $this->sourceAccountId; - } - - /** - * @param mixed $sourceAccountId - */ - public function setSourceAccountId($sourceAccountId) - { - $this->sourceAccountId = $sourceAccountId; - } - - /** - * @return mixed - */ - public function getFromAccountId() - { - return $this->fromAccountId; - } - - /** - * @param mixed $fromAccountId - */ - public function setFromAccountId($fromAccountId) - { - $this->fromAccountId = $fromAccountId; - } - - /** - * @return string - */ - public function getToAccountId() - { - return $this->toAccountId; - } - - /** - * @return string - */ - public function getDestinationAccountId() - { - return $this->toAccountId; - } - - /** - * @param mixed $toAccountId - */ - public function setToAccountId($toAccountId) - { - $this->toAccountId = $toAccountId; - } - - /** - * @return AssetAmount - */ - public function getAmount() - { - return $this->amount; - } - - /** - * @param AssetAmount $amount - */ - public function setAmount(AssetAmount $amount) - { - $this->amount = $amount; - } -} +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $toAccountId + * @param $amount + * @return Payment + */ + public static function newNativeAssetPayment($toAccountId, $amount, $fromAccountId, $sourceAccountId = null) + { + $payment = new Payment(null); + $payment->toAccountId = $toAccountId; + $payment->amount = new AssetAmount($amount); + $payment->fromAccountId = $fromAccountId; + + if ($sourceAccountId === null) $payment->sourceAccountId = $fromAccountId; + + return $payment; + } + + /** + * @param $id + * @param $type + */ + public function __construct($id) + { + parent::__construct($id, Operation::TYPE_PAYMENT); + + $this->amount = new AssetAmount('0'); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + $this->sourceAccountId = $rawData['source_account']; + + if (isset($rawData['from'])) $this->fromAccountId = $rawData['from']; + if (isset($rawData['to'])) $this->toAccountId = $rawData['to']; + + $assetAmount = null; + // Native assets + if ('native' == $rawData['asset_type']) { + $assetAmount = new AssetAmount($rawData['amount']); + } + // Custom assets + else { + $assetAmount = new AssetAmount($rawData['amount'], $rawData['asset_type']); + $assetAmount->setAssetIssuerAccountId($rawData['asset_issuer']); + $assetAmount->setAssetCode($rawData['asset_code']); + } + + $this->amount = $assetAmount; + } + + public function getAssetTransferType() + { + return $this->type; + } + + public function getAssetAmount() + { + return $this->amount; + } + + /** + * @return bool + */ + public function isNativeAsset() + { + return $this->amount->isNativeAsset(); + } + + /** + * @return mixed + */ + public function getSourceAccountId() + { + return $this->sourceAccountId; + } + + /** + * @param mixed $sourceAccountId + */ + public function setSourceAccountId($sourceAccountId) + { + $this->sourceAccountId = $sourceAccountId; + } + + /** + * @return mixed + */ + public function getFromAccountId() + { + return $this->fromAccountId; + } + + /** + * @param mixed $fromAccountId + */ + public function setFromAccountId($fromAccountId) + { + $this->fromAccountId = $fromAccountId; + } + + /** + * @return string + */ + public function getToAccountId() + { + return $this->toAccountId; + } + + /** + * @return string + */ + public function getDestinationAccountId() + { + return $this->toAccountId; + } + + /** + * @param mixed $toAccountId + */ + public function setToAccountId($toAccountId) + { + $this->toAccountId = $toAccountId; + } + + /** + * @return AssetAmount + */ + public function getAmount() + { + return $this->amount; + } + + /** + * @param AssetAmount $amount + */ + public function setAmount(AssetAmount $amount) + { + $this->amount = $amount; + } +} diff --git a/src/Model/RestApiModel.php b/src/Model/RestApiModel.php index 31741b4..20cb4ab 100755 --- a/src/Model/RestApiModel.php +++ b/src/Model/RestApiModel.php @@ -1,129 +1,129 @@ -rawData = $rawData; - - if (isset($rawData['_links'])) $this->links = $rawData['_links']; - if (isset($rawData['id'])) $this->id = $rawData['id']; - } - - /** - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * @param string $id - */ - public function setId($id) - { - $this->id = $id; - } - - /** - * @return ApiClient - */ - public function getApiClient() - { - return $this->apiClient; - } - - /** - * @param ApiClient $apiClient - */ - public function setApiClient($apiClient) - { - $this->apiClient = $apiClient; - } - - /** - * @return array - */ - public function getLinks() - { - return $this->links; - } - - /** - * @param array $links - */ - public function setLinks($links) - { - $this->links = $links; - } - - /** - * @return string - */ - public function getPagingToken() - { - return $this->pagingToken; - } - - /** - * @param string $pagingToken - */ - public function setPagingToken($pagingToken) - { - $this->pagingToken = $pagingToken; - } - - /** - * @return array - */ - public function getRawData() - { - return $this->rawData; - } - - /** - * @param array $rawData - */ - public function setRawData($rawData) - { - $this->rawData = $rawData; - } +rawData = $rawData; + + if (isset($rawData['_links'])) $this->links = $rawData['_links']; + if (isset($rawData['id'])) $this->id = $rawData['id']; + } + + /** + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * @param string $id + */ + public function setId($id) + { + $this->id = $id; + } + + /** + * @return ApiClient + */ + public function getApiClient() + { + return $this->apiClient; + } + + /** + * @param ApiClient $apiClient + */ + public function setApiClient($apiClient) + { + $this->apiClient = $apiClient; + } + + /** + * @return array + */ + public function getLinks() + { + return $this->links; + } + + /** + * @param array $links + */ + public function setLinks($links) + { + $this->links = $links; + } + + /** + * @return string + */ + public function getPagingToken() + { + return $this->pagingToken; + } + + /** + * @param string $pagingToken + */ + public function setPagingToken($pagingToken) + { + $this->pagingToken = $pagingToken; + } + + /** + * @return array + */ + public function getRawData() + { + return $this->rawData; + } + + /** + * @param array $rawData + */ + public function setRawData($rawData) + { + $this->rawData = $rawData; + } } \ No newline at end of file diff --git a/src/Model/SetOptionsOperation.php b/src/Model/SetOptionsOperation.php index c1aee42..944cf4b 100644 --- a/src/Model/SetOptionsOperation.php +++ b/src/Model/SetOptionsOperation.php @@ -1,303 +1,303 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $id - * @param $type - */ - public function __construct($id, $type) - { - parent::__construct($id, Operation::TYPE_SET_OPTIONS); - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - if (isset($rawData['signer_key'])) $this->signerKey = $rawData['signer_key']; - if (isset($rawData['signer_weight'])) $this->signerWeight = $rawData['signer_weight']; - if (isset($rawData['master_key_weight'])) $this->masterKeyWeight = $rawData['master_key_weight']; - - if (isset($rawData['low_threshold'])) $this->lowThreshold = $rawData['low_threshold']; - if (isset($rawData['med_threshold'])) $this->mediumThreshold = $rawData['med_threshold']; - if (isset($rawData['high_threshold'])) $this->highThreshold = $rawData['high_threshold']; - - if (isset($rawData['set_flags'])) $this->setFlagsI = $rawData['set_flags']; - if (isset($rawData['set_flags_s'])) $this->setFlagsS = $rawData['set_flags_s']; - if (isset($rawData['clear_flags'])) $this->clearFlagsI = $rawData['clear_flags']; - if (isset($rawData['clear_flags_s'])) $this->clearFlagsS = $rawData['clear_flags_s']; - } - - /** - * @return string - */ - public function getSignerKey() - { - return $this->signerKey; - } - - /** - * @param string $signerKey - */ - public function setSignerKey($signerKey) - { - $this->signerKey = $signerKey; - } - - /** - * @return int - */ - public function getSignerWeight() - { - return $this->signerWeight; - } - - /** - * @param int $signerWeight - */ - public function setSignerWeight($signerWeight) - { - $this->signerWeight = $signerWeight; - } - - /** - * @return int - */ - public function getMasterKeyWeight() - { - return $this->masterKeyWeight; - } - - /** - * @param int $masterKeyWeight - */ - public function setMasterKeyWeight($masterKeyWeight) - { - $this->masterKeyWeight = $masterKeyWeight; - } - - /** - * @return int - */ - public function getLowThreshold() - { - return $this->lowThreshold; - } - - /** - * @param int $lowThreshold - */ - public function setLowThreshold($lowThreshold) - { - $this->lowThreshold = $lowThreshold; - } - - /** - * @return int - */ - public function getMediumThreshold() - { - return $this->mediumThreshold; - } - - /** - * @param int $mediumThreshold - */ - public function setMediumThreshold($mediumThreshold) - { - $this->mediumThreshold = $mediumThreshold; - } - - /** - * @return int - */ - public function getHighThreshold() - { - return $this->highThreshold; - } - - /** - * @param int $highThreshold - */ - public function setHighThreshold($highThreshold) - { - $this->highThreshold = $highThreshold; - } - - /** - * @return string - */ - public function getHomeDomain() - { - return $this->homeDomain; - } - - /** - * @param string $homeDomain - */ - public function setHomeDomain($homeDomain) - { - $this->homeDomain = $homeDomain; - } - - /** - * @return array - */ - public function getSetFlagsI() - { - return $this->setFlagsI; - } - - /** - * @param array $setFlagsI - */ - public function setSetFlagsI($setFlagsI) - { - $this->setFlagsI = $setFlagsI; - } - - /** - * @return array - */ - public function getSetFlagsS() - { - return $this->setFlagsS; - } - - /** - * @param array $setFlagsS - */ - public function setSetFlagsS($setFlagsS) - { - $this->setFlagsS = $setFlagsS; - } - - /** - * @return array - */ - public function getClearFlagsI() - { - return $this->clearFlagsI; - } - - /** - * @param array $clearFlagsI - */ - public function setClearFlagsI($clearFlagsI) - { - $this->clearFlagsI = $clearFlagsI; - } - - /** - * @return array - */ - public function getClearFlagsS() - { - return $this->clearFlagsS; - } - - /** - * @param array $clearFlagsS - */ - public function setClearFlagsS($clearFlagsS) - { - $this->clearFlagsS = $clearFlagsS; - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $id + * @param $type + */ + public function __construct($id, $type) + { + parent::__construct($id, Operation::TYPE_SET_OPTIONS); + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + if (isset($rawData['signer_key'])) $this->signerKey = $rawData['signer_key']; + if (isset($rawData['signer_weight'])) $this->signerWeight = $rawData['signer_weight']; + if (isset($rawData['master_key_weight'])) $this->masterKeyWeight = $rawData['master_key_weight']; + + if (isset($rawData['low_threshold'])) $this->lowThreshold = $rawData['low_threshold']; + if (isset($rawData['med_threshold'])) $this->mediumThreshold = $rawData['med_threshold']; + if (isset($rawData['high_threshold'])) $this->highThreshold = $rawData['high_threshold']; + + if (isset($rawData['set_flags'])) $this->setFlagsI = $rawData['set_flags']; + if (isset($rawData['set_flags_s'])) $this->setFlagsS = $rawData['set_flags_s']; + if (isset($rawData['clear_flags'])) $this->clearFlagsI = $rawData['clear_flags']; + if (isset($rawData['clear_flags_s'])) $this->clearFlagsS = $rawData['clear_flags_s']; + } + + /** + * @return string + */ + public function getSignerKey() + { + return $this->signerKey; + } + + /** + * @param string $signerKey + */ + public function setSignerKey($signerKey) + { + $this->signerKey = $signerKey; + } + + /** + * @return int + */ + public function getSignerWeight() + { + return $this->signerWeight; + } + + /** + * @param int $signerWeight + */ + public function setSignerWeight($signerWeight) + { + $this->signerWeight = $signerWeight; + } + + /** + * @return int + */ + public function getMasterKeyWeight() + { + return $this->masterKeyWeight; + } + + /** + * @param int $masterKeyWeight + */ + public function setMasterKeyWeight($masterKeyWeight) + { + $this->masterKeyWeight = $masterKeyWeight; + } + + /** + * @return int + */ + public function getLowThreshold() + { + return $this->lowThreshold; + } + + /** + * @param int $lowThreshold + */ + public function setLowThreshold($lowThreshold) + { + $this->lowThreshold = $lowThreshold; + } + + /** + * @return int + */ + public function getMediumThreshold() + { + return $this->mediumThreshold; + } + + /** + * @param int $mediumThreshold + */ + public function setMediumThreshold($mediumThreshold) + { + $this->mediumThreshold = $mediumThreshold; + } + + /** + * @return int + */ + public function getHighThreshold() + { + return $this->highThreshold; + } + + /** + * @param int $highThreshold + */ + public function setHighThreshold($highThreshold) + { + $this->highThreshold = $highThreshold; + } + + /** + * @return string + */ + public function getHomeDomain() + { + return $this->homeDomain; + } + + /** + * @param string $homeDomain + */ + public function setHomeDomain($homeDomain) + { + $this->homeDomain = $homeDomain; + } + + /** + * @return array + */ + public function getSetFlagsI() + { + return $this->setFlagsI; + } + + /** + * @param array $setFlagsI + */ + public function setSetFlagsI($setFlagsI) + { + $this->setFlagsI = $setFlagsI; + } + + /** + * @return array + */ + public function getSetFlagsS() + { + return $this->setFlagsS; + } + + /** + * @param array $setFlagsS + */ + public function setSetFlagsS($setFlagsS) + { + $this->setFlagsS = $setFlagsS; + } + + /** + * @return array + */ + public function getClearFlagsI() + { + return $this->clearFlagsI; + } + + /** + * @param array $clearFlagsI + */ + public function setClearFlagsI($clearFlagsI) + { + $this->clearFlagsI = $clearFlagsI; + } + + /** + * @return array + */ + public function getClearFlagsS() + { + return $this->clearFlagsS; + } + + /** + * @param array $clearFlagsS + */ + public function setClearFlagsS($clearFlagsS) + { + $this->clearFlagsS = $clearFlagsS; + } } \ No newline at end of file diff --git a/src/Model/StellarAmount.php b/src/Model/StellarAmount.php index 0d3f246..131c1fc 100644 --- a/src/Model/StellarAmount.php +++ b/src/Model/StellarAmount.php @@ -1,123 +1,128 @@ -readInteger64())); + } + + /** + * StellarAmount constructor. + * + * @param $lumensOrBigIntegerStroops + * @throws \ErrorException + */ + public function __construct($lumensOrBigIntegerStroops) + { + // This class assumes 64-bit support + MathSafety::require64Bit(); + + $this->stroopScaleBignum = new BigInteger(static::STROOP_SCALE); + $this->maxSignedStroops64 = new BigInteger('9223372036854775807'); + + // Store everything as a BigInteger representing stroops + if ($lumensOrBigIntegerStroops instanceof BigInteger) { + $this->stroops = $lumensOrBigIntegerStroops; + } + // Can also pass in another StellarAmount + else if ($lumensOrBigIntegerStroops instanceof StellarAmount) { + $this->stroops = clone $lumensOrBigIntegerStroops->getUnscaledBigInteger(); + } + else { + $lumensOrBigIntegerStroops = number_format($lumensOrBigIntegerStroops, 7, '.', ''); + $parts = explode('.', $lumensOrBigIntegerStroops); + $unscaledAmount = new BigInteger('0'); + + // Everything to the left of the decimal point + if ($parts[0]) { + $unscaledAmountLeft = (new BigInteger($parts[0]))->multiply(new BigInteger(static::STROOP_SCALE)); + $unscaledAmount = $unscaledAmount->add($unscaledAmountLeft); + } + + // Add everything to the right of the decimal point + if (count($parts) == 2 && str_replace('0', '', $parts[1]) != '') { + // Should be a total of 7 decimal digits to the right of the decimal + $unscaledAmountRight = str_pad($parts[1], 7, '0',STR_PAD_RIGHT); + $unscaledAmount = $unscaledAmount->add(new BigInteger($unscaledAmountRight)); + } + + $this->stroops = $unscaledAmount; + } + + // Ensure amount of stroops doesn't exceed the maximum + $compared = $this->stroops->compare($this->maxSignedStroops64); + if ($compared > 0) { + throw new \InvalidArgumentException('Maximum value exceeded. Value cannot be larger than 9223372036854775807 stroops (922337203685.4775807 XLM)'); + } + + // Ensure amount is not negative + $zero = new BigInteger('0'); + $compared = $this->stroops->compare($zero); + if ($compared < 0) { + throw new \InvalidArgumentException('Amount cannot be negative'); + } + } + /** - * The largest amount of stroops that can fit in a signed int64 - * @var BigInteger - */ - protected $maxSignedStroops64; - - /** - * Returns the maximum supported amount - * - * @return StellarAmount - */ - public static function newMaximum() - { - return new StellarAmount(new BigInteger('9223372036854775807')); - } - - /** - * Reads a StellarAmount from a SIGNED 64-bit integer + * Returns the scaled value as a string with 7 decimal places (Stellar precision). * - * @param XdrBuffer $xdr - * @return StellarAmount - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - return new StellarAmount(new BigInteger($xdr->readInteger64())); - } - - /** - * StellarAmount constructor. + * Example: "1.0000000" or "12.3456789". Use this for display. + * For storage/comparison, prefer stroops via {@see StellarAmount::getUnscaledString()}. * - * @param $lumensOrBigIntegerStroops - * @throws \ErrorException - */ - public function __construct($lumensOrBigIntegerStroops) - { - // This class assumes 64-bit support - MathSafety::require64Bit(); - - $this->stroopScaleBignum = new BigInteger(static::STROOP_SCALE); - $this->maxSignedStroops64 = new BigInteger('9223372036854775807'); - - // Store everything as a BigInteger representing stroops - if ($lumensOrBigIntegerStroops instanceof BigInteger) { - $this->stroops = $lumensOrBigIntegerStroops; - } - // Can also pass in another StellarAmount - else if ($lumensOrBigIntegerStroops instanceof StellarAmount) { - $this->stroops = clone $lumensOrBigIntegerStroops->getUnscaledBigInteger(); - } - else { - $lumensOrBigIntegerStroops = number_format($lumensOrBigIntegerStroops, 7, '.', ''); - $parts = explode('.', $lumensOrBigIntegerStroops); - $unscaledAmount = new BigInteger('0'); - - // Everything to the left of the decimal point - if ($parts[0]) { - $unscaledAmountLeft = (new BigInteger($parts[0]))->multiply(new BigInteger(static::STROOP_SCALE)); - $unscaledAmount = $unscaledAmount->add($unscaledAmountLeft); - } - - // Add everything to the right of the decimal point - if (count($parts) == 2 && str_replace('0', '', $parts[1]) != '') { - // Should be a total of 7 decimal digits to the right of the decimal - $unscaledAmountRight = str_pad($parts[1], 7, '0',STR_PAD_RIGHT); - $unscaledAmount = $unscaledAmount->add(new BigInteger($unscaledAmountRight)); - } - - $this->stroops = $unscaledAmount; - } - - // Ensure amount of stroops doesn't exceed the maximum - $compared = $this->stroops->compare($this->maxSignedStroops64); - if ($compared > 0) { - throw new \InvalidArgumentException('Maximum value exceeded. Value cannot be larger than 9223372036854775807 stroops (922337203685.4775807 XLM)'); - } - - // Ensure amount is not negative - $zero = new BigInteger('0'); - $compared = $this->stroops->compare($zero); - if ($compared < 0) { - throw new \InvalidArgumentException('Amount cannot be negative'); - } - } - - /** - * @return float|int + * @return string 7-decimal string suitable for display */ public function getScaledValue() { @@ -128,24 +133,26 @@ public function getScaledValue() $number = intval($quotient->toString()) + (intval($remainder->toString()) / intval($this->stroopScaleBignum->toString())); return number_format($number, 7, '.', ''); } - + /** - * Returns the raw value in stroops as a string + * Returns the raw value in stroops as an integer string (no decimals). * - * @return string - */ - public function getUnscaledString() - { - return $this->stroops->toString(); - } - - /** - * Returns the raw value in stroops + * Example: "10000000" represents 1 XLM. * - * @return BigInteger + * @return string Integer string of stroops suitable for storage/comparison */ - public function getUnscaledBigInteger() - { - return $this->stroops; - } -} \ No newline at end of file + public function getUnscaledString() + { + return $this->stroops->toString(); + } + + /** + * Returns the raw value in stroops + * + * @return BigInteger + */ + public function getUnscaledBigInteger() + { + return $this->stroops; + } +} diff --git a/src/Model/Transaction.php b/src/Model/Transaction.php index 7c3594b..663c231 100755 --- a/src/Model/Transaction.php +++ b/src/Model/Transaction.php @@ -1,438 +1,438 @@ -loadFromRawResponseData($rawData); - - return $object; - } - - /** - * @param $id - * @param $hash - */ - public function __construct($id, $hash) - { - $this->id = $id; - $this->hash = $hash; - } - - /** - * @param $rawData - */ - public function loadFromRawResponseData($rawData) - { - parent::loadFromRawResponseData($rawData); - - // todo: should be a Memo object? - if (isset($rawData['ledger'])) $this->ledger = $rawData['ledger']; - if (isset($rawData['created_at'])) $this->createdAt = \DateTime::createFromFormat(DATE_ISO8601, $rawData['created_at']); - if (isset($rawData['source_account'])) $this->sourceAccountId = $rawData['source_account']; - if (isset($rawData['source_account_sequence'])) $this->sourceAccountSequence = $rawData['source_account_sequence']; - if (isset($rawData['fee_paid'])) $this->feePaid = $rawData['fee_paid']; - if (isset($rawData['operation_count'])) $this->operationCount = $rawData['operation_count']; - if (isset($rawData['envelope_xdr'])) $this->envelopeXdr = $rawData['envelope_xdr']; - if (isset($rawData['result_xdr'])) $this->resultXdr = $rawData['result_xdr']; - if (isset($rawData['result_meta_xdr'])) $this->resultMetaXdr = $rawData['result_meta_xdr']; - if (isset($rawData['fee_meta_xdr'])) $this->feeMetaXdr = $rawData['fee_meta_xdr']; - if (isset($rawData['result_code'])) $this->resultCodeI = $rawData['result_code']; - if (isset($rawData['result_code_s'])) $this->resultCodeS = $rawData['result_code_s']; - if (isset($rawData['memo_type'])) $this->memoType = $rawData['memo_type']; - if (isset($rawData['memo'])) $this->memo = $rawData['memo']; - } - - /** - * @param null $sinceCursor - * @param int $limit - * @return array|AssetTransferInterface[]|RestApiModel[] - */ - public function getPayments($sinceCursor = null, $limit = 50) - { - $payments = []; - - $url = sprintf('/transactions/%s/payments', $this->hash); - $params = []; - - if ($sinceCursor) $params['cursor'] = $sinceCursor; - if ($limit) $params['limit'] = $limit; - - if ($params) { - $url .= '?' . http_build_query($params); - } - - $response = $this->apiClient->get($url); - - $rawRecords = $response->getRecords(); - - foreach ($rawRecords as $rawRecord) { - switch ($rawRecord['type']) { - case 'create_account': - $result = CreateAccountOperation::fromRawResponseData($rawRecord); - break; - case 'payment': - $result = Payment::fromRawResponseData($rawRecord); - break; - case 'account_merge': - $result = AccountMergeOperation::fromRawResponseData($rawRecord); - break; - case 'path_payment': - $result = PathPayment::fromRawResponseData($rawRecord); - break; - } - - $result->setApiClient($this->getApiClient()); - - $payments[] = $result; - } - - return $payments; - } - - /** - * @return string - */ - public function getHash() - { - return $this->hash; - } - - /** - * @param string $hash - */ - public function setHash($hash) - { - $this->hash = $hash; - } - - /** - * @return mixed - */ - public function getMemoType() - { - return $this->memoType; - } - - /** - * @param mixed $memoType - */ - public function setMemoType($memoType) - { - $this->memoType = $memoType; - } - - /** - * @return mixed - */ - public function getMemo() - { - return $this->memo; - } - - /** - * @param mixed $memo - */ - public function setMemo($memo) - { - $this->memo = $memo; - } - - /** - * @return mixed - */ - public function getSourceAccountId() - { - return $this->sourceAccountId; - } - - /** - * @param mixed $sourceAccountId - */ - public function setSourceAccountId($sourceAccountId) - { - $this->sourceAccountId = $sourceAccountId; - } - - /** - * @return string - */ - public function getLedger() - { - return $this->ledger; - } - - /** - * @param string $ledger - */ - public function setLedger($ledger) - { - $this->ledger = $ledger; - } - - /** - * @return string - */ - public function getSourceAccountSequence() - { - return $this->sourceAccountSequence; - } - - /** - * @param string $sourceAccountSequence - */ - public function setSourceAccountSequence($sourceAccountSequence) - { - $this->sourceAccountSequence = $sourceAccountSequence; - } - - /** - * @return int - */ - public function getFeePaid() - { - return $this->feePaid; - } - - /** - * @param int $feePaid - */ - public function setFeePaid($feePaid) - { - $this->feePaid = $feePaid; - } - - /** - * @return int - */ - public function getOperationCount() - { - return $this->operationCount; - } - - /** - * @param int $operationCount - */ - public function setOperationCount($operationCount) - { - $this->operationCount = $operationCount; - } - - /** - * @return int - */ - public function getResultCodeI() - { - return $this->resultCodeI; - } - - /** - * @param int $resultCodeI - */ - public function setResultCodeI($resultCodeI) - { - $this->resultCodeI = $resultCodeI; - } - - /** - * @return string - */ - public function getResultCodeS() - { - return $this->resultCodeS; - } - - /** - * @param string $resultCodeS - */ - public function setResultCodeS($resultCodeS) - { - $this->resultCodeS = $resultCodeS; - } - - /** - * @return string - */ - public function getEnvelopeXdr() - { - return $this->envelopeXdr; - } - - /** - * @param string $envelopeXdr - */ - public function setEnvelopeXdr($envelopeXdr) - { - $this->envelopeXdr = $envelopeXdr; - } - - /** - * @return string - */ - public function getResultXdr() - { - return $this->resultXdr; - } - - /** - * @param string $resultXdr - */ - public function setResultXdr($resultXdr) - { - $this->resultXdr = $resultXdr; - } - - /** - * @return string - */ - public function getResultMetaXdr() - { - return $this->resultMetaXdr; - } - - /** - * @param string $resultMetaXdr - */ - public function setResultMetaXdr($resultMetaXdr) - { - $this->resultMetaXdr = $resultMetaXdr; - } - - /** - * @return string - */ - public function getFeeMetaXdr() - { - return $this->feeMetaXdr; - } - - /** - * @param string $feeMetaXdr - */ - public function setFeeMetaXdr($feeMetaXdr) - { - $this->feeMetaXdr = $feeMetaXdr; - } - - /** - * @return \DateTime - */ - public function getCreatedAt() - { - return $this->createdAt; - } - - /** - * @param \DateTime $createdAt - */ - public function setCreatedAt($createdAt) - { - $this->createdAt = $createdAt; - } +loadFromRawResponseData($rawData); + + return $object; + } + + /** + * @param $id + * @param $hash + */ + public function __construct($id, $hash) + { + $this->id = $id; + $this->hash = $hash; + } + + /** + * @param $rawData + */ + public function loadFromRawResponseData($rawData) + { + parent::loadFromRawResponseData($rawData); + + // todo: should be a Memo object? + if (isset($rawData['ledger'])) $this->ledger = $rawData['ledger']; + if (isset($rawData['created_at'])) $this->createdAt = \DateTime::createFromFormat(DATE_ISO8601, $rawData['created_at']); + if (isset($rawData['source_account'])) $this->sourceAccountId = $rawData['source_account']; + if (isset($rawData['source_account_sequence'])) $this->sourceAccountSequence = $rawData['source_account_sequence']; + if (isset($rawData['fee_paid'])) $this->feePaid = $rawData['fee_paid']; + if (isset($rawData['operation_count'])) $this->operationCount = $rawData['operation_count']; + if (isset($rawData['envelope_xdr'])) $this->envelopeXdr = $rawData['envelope_xdr']; + if (isset($rawData['result_xdr'])) $this->resultXdr = $rawData['result_xdr']; + if (isset($rawData['result_meta_xdr'])) $this->resultMetaXdr = $rawData['result_meta_xdr']; + if (isset($rawData['fee_meta_xdr'])) $this->feeMetaXdr = $rawData['fee_meta_xdr']; + if (isset($rawData['result_code'])) $this->resultCodeI = $rawData['result_code']; + if (isset($rawData['result_code_s'])) $this->resultCodeS = $rawData['result_code_s']; + if (isset($rawData['memo_type'])) $this->memoType = $rawData['memo_type']; + if (isset($rawData['memo'])) $this->memo = $rawData['memo']; + } + + /** + * @param null $sinceCursor + * @param int $limit + * @return array|AssetTransferInterface[]|RestApiModel[] + */ + public function getPayments($sinceCursor = null, $limit = 50) + { + $payments = []; + + $url = sprintf('/transactions/%s/payments', $this->hash); + $params = []; + + if ($sinceCursor) $params['cursor'] = $sinceCursor; + if ($limit) $params['limit'] = $limit; + + if ($params) { + $url .= '?' . http_build_query($params); + } + + $response = $this->apiClient->get($url); + + $rawRecords = $response->getRecords(); + + foreach ($rawRecords as $rawRecord) { + switch ($rawRecord['type']) { + case 'create_account': + $result = CreateAccountOperation::fromRawResponseData($rawRecord); + break; + case 'payment': + $result = Payment::fromRawResponseData($rawRecord); + break; + case 'account_merge': + $result = AccountMergeOperation::fromRawResponseData($rawRecord); + break; + case 'path_payment': + $result = PathPayment::fromRawResponseData($rawRecord); + break; + } + + $result->setApiClient($this->getApiClient()); + + $payments[] = $result; + } + + return $payments; + } + + /** + * @return string + */ + public function getHash() + { + return $this->hash; + } + + /** + * @param string $hash + */ + public function setHash($hash) + { + $this->hash = $hash; + } + + /** + * @return mixed + */ + public function getMemoType() + { + return $this->memoType; + } + + /** + * @param mixed $memoType + */ + public function setMemoType($memoType) + { + $this->memoType = $memoType; + } + + /** + * @return mixed + */ + public function getMemo() + { + return $this->memo; + } + + /** + * @param mixed $memo + */ + public function setMemo($memo) + { + $this->memo = $memo; + } + + /** + * @return mixed + */ + public function getSourceAccountId() + { + return $this->sourceAccountId; + } + + /** + * @param mixed $sourceAccountId + */ + public function setSourceAccountId($sourceAccountId) + { + $this->sourceAccountId = $sourceAccountId; + } + + /** + * @return string + */ + public function getLedger() + { + return $this->ledger; + } + + /** + * @param string $ledger + */ + public function setLedger($ledger) + { + $this->ledger = $ledger; + } + + /** + * @return string + */ + public function getSourceAccountSequence() + { + return $this->sourceAccountSequence; + } + + /** + * @param string $sourceAccountSequence + */ + public function setSourceAccountSequence($sourceAccountSequence) + { + $this->sourceAccountSequence = $sourceAccountSequence; + } + + /** + * @return int + */ + public function getFeePaid() + { + return $this->feePaid; + } + + /** + * @param int $feePaid + */ + public function setFeePaid($feePaid) + { + $this->feePaid = $feePaid; + } + + /** + * @return int + */ + public function getOperationCount() + { + return $this->operationCount; + } + + /** + * @param int $operationCount + */ + public function setOperationCount($operationCount) + { + $this->operationCount = $operationCount; + } + + /** + * @return int + */ + public function getResultCodeI() + { + return $this->resultCodeI; + } + + /** + * @param int $resultCodeI + */ + public function setResultCodeI($resultCodeI) + { + $this->resultCodeI = $resultCodeI; + } + + /** + * @return string + */ + public function getResultCodeS() + { + return $this->resultCodeS; + } + + /** + * @param string $resultCodeS + */ + public function setResultCodeS($resultCodeS) + { + $this->resultCodeS = $resultCodeS; + } + + /** + * @return string + */ + public function getEnvelopeXdr() + { + return $this->envelopeXdr; + } + + /** + * @param string $envelopeXdr + */ + public function setEnvelopeXdr($envelopeXdr) + { + $this->envelopeXdr = $envelopeXdr; + } + + /** + * @return string + */ + public function getResultXdr() + { + return $this->resultXdr; + } + + /** + * @param string $resultXdr + */ + public function setResultXdr($resultXdr) + { + $this->resultXdr = $resultXdr; + } + + /** + * @return string + */ + public function getResultMetaXdr() + { + return $this->resultMetaXdr; + } + + /** + * @param string $resultMetaXdr + */ + public function setResultMetaXdr($resultMetaXdr) + { + $this->resultMetaXdr = $resultMetaXdr; + } + + /** + * @return string + */ + public function getFeeMetaXdr() + { + return $this->feeMetaXdr; + } + + /** + * @param string $feeMetaXdr + */ + public function setFeeMetaXdr($feeMetaXdr) + { + $this->feeMetaXdr = $feeMetaXdr; + } + + /** + * @return \DateTime + */ + public function getCreatedAt() + { + return $this->createdAt; + } + + /** + * @param \DateTime $createdAt + */ + public function setCreatedAt($createdAt) + { + $this->createdAt = $createdAt; + } } \ No newline at end of file diff --git a/src/Server.php b/src/Server.php index 2540e73..ac79ed9 100755 --- a/src/Server.php +++ b/src/Server.php @@ -1,91 +1,91 @@ -isTestnet = true; - - return $server; - } - - /** - * @return Server - */ - public static function publicNet() - { - $server = new Server(ApiClient::newPublicClient()); - - return $server; - } - - /** - * Connects to a custom network - * - * @param $horizonBaseUrl - * @param $networkPassphrase - * @return Server - */ - public static function customNet($horizonBaseUrl, $networkPassphrase) - { - return new Server(ApiClient::newCustomClient($horizonBaseUrl, $networkPassphrase)); - } - - public function __construct(ApiClient $apiClient) - { - $this->apiClient = $apiClient; - $this->isTestnet = false; - } - - /** - * Returns the Account that matches $accountId or null if the account does - * not exist - * - * @param $accountId Keypair|string the public account ID - * @return Account|null - * @throws Horizon\Exception\HorizonException - */ +isTestnet = true; + + return $server; + } + + /** + * @return Server + */ + public static function publicNet() + { + $server = new Server(ApiClient::newPublicClient()); + + return $server; + } + + /** + * Connects to a custom network + * + * @param $horizonBaseUrl + * @param $networkPassphrase + * @return Server + */ + public static function customNet($horizonBaseUrl, $networkPassphrase) + { + return new Server(ApiClient::newCustomClient($horizonBaseUrl, $networkPassphrase)); + } + + public function __construct(ApiClient $apiClient) + { + $this->apiClient = $apiClient; + $this->isTestnet = false; + } + + /** + * Returns the Account that matches $accountId or null if the account does + * not exist + * + * @param $accountId Keypair|string the public account ID + * @return Account|null + * @throws Horizon\Exception\HorizonException + */ public function getAccount($accountId) { // Cannot be empty if (!$accountId) throw new InvalidArgumentException('Empty accountId'); - - if ($accountId instanceof Keypair) { - $accountId = $accountId->getPublicKey(); - } - + + if ($accountId instanceof Keypair) { + $accountId = $accountId->getPublicKey(); + } + try { $response = $this->apiClient->get(sprintf('/accounts/%s', $accountId)); } @@ -99,146 +99,151 @@ public function getAccount($accountId) throw $e; } + // Some Horizon deployments return a JSON body with status 404 instead of throwing + if ($response && $response->getField('status') === 404) { + return null; + } + $account = Account::fromHorizonResponse($response); $account->setApiClient($this->apiClient); return $account; } - - /** - * Returns true if the account exists on this server and has been funded - * - * @param $accountId - * @return bool - * @throws HorizonException - * @throws \ErrorException - */ - public function accountExists($accountId) - { - // Handle basic errors such as malformed account IDs - try { - $account = $this->getAccount($accountId); - } catch (\InvalidArgumentException $e) { - return false; - } - - // Account ID may be valid but hasn't been funded yet - if (!$account) return false; - - return $account->getNativeBalanceStroops() != '0'; - } - - /** - * @param $accountId string|Keypair - * @return TransactionBuilder - */ - public function buildTransaction($accountId) - { - if ($accountId instanceof Keypair) { - $accountId = $accountId->getPublicKey(); - } - - return (new TransactionBuilder($accountId)) - ->setApiClient($this->apiClient) - ->setSigningProvider($this->signingProvider) - ; - } - - /** - * @param $transactionHash - * @return array|Payment[] - */ - public function getPaymentsByTransactionHash($transactionHash) - { - $url = sprintf('/transactions/%s/payments', $transactionHash); - - $response = $this->apiClient->get($url); - - $payments = []; - foreach ($response->getRecords() as $rawRecord) { - $payments[] = Payment::fromRawResponseData($rawRecord); - } - - return $payments; - } - - /** - * @param $accountId - * @return bool - * @throws Horizon\Exception\HorizonException - */ - public function fundAccount($accountId) - { - if ($accountId instanceof Keypair) { - $accountId = $accountId->getPublicKey(); - } - - try { - $this->apiClient->get(sprintf('/friendbot?addr=%s', $accountId)); - return true; - } - catch (HorizonException $e) { - // Account has already been funded - if ($e->getHttpStatusCode() == 400) { - return false; - } - - // Unexpected exception - throw $e; - } - - } - - /** - * Submits a base64-encoded transaction to the Stellar network. - * - * No additional validation is performed on this transaction - * - * @param $base64TransactionEnvelope - * @return Horizon\Api\HorizonResponse - */ - public function submitB64Transaction($base64TransactionEnvelope) - { - return $this->apiClient->submitB64Transaction($base64TransactionEnvelope); - } - - /** - * @return string - */ - public function getHorizonBaseUrl() - { - return $this->apiClient->getBaseUrl(); - } - - /** - * @return SigningInterface - */ - public function getSigningProvider() - { - return $this->signingProvider; - } - - /** - * @param SigningInterface $signingProvider - */ - public function setSigningProvider($signingProvider) - { - $this->signingProvider = $signingProvider; - } - - /** - * @return ApiClient - */ - public function getApiClient() - { - return $this->apiClient; - } - - /** - * @param ApiClient $apiClient - */ - public function setApiClient($apiClient) - { - $this->apiClient = $apiClient; - } -} \ No newline at end of file + + /** + * Returns true if the account exists on this server and has been funded + * + * @param $accountId + * @return bool + * @throws HorizonException + * @throws \ErrorException + */ + public function accountExists($accountId) + { + // Handle basic errors such as malformed account IDs + try { + $account = $this->getAccount($accountId); + } catch (\InvalidArgumentException $e) { + return false; + } + + // Account ID may be valid but hasn't been funded yet + if (!$account) return false; + + return $account->getNativeBalanceStroops() != '0'; + } + + /** + * @param $accountId string|Keypair + * @return TransactionBuilder + */ + public function buildTransaction($accountId) + { + if ($accountId instanceof Keypair) { + $accountId = $accountId->getPublicKey(); + } + + return (new TransactionBuilder($accountId)) + ->setApiClient($this->apiClient) + ->setSigningProvider($this->signingProvider) + ; + } + + /** + * @param $transactionHash + * @return array|Payment[] + */ + public function getPaymentsByTransactionHash($transactionHash) + { + $url = sprintf('/transactions/%s/payments', $transactionHash); + + $response = $this->apiClient->get($url); + + $payments = []; + foreach ($response->getRecords() as $rawRecord) { + $payments[] = Payment::fromRawResponseData($rawRecord); + } + + return $payments; + } + + /** + * @param $accountId + * @return bool + * @throws Horizon\Exception\HorizonException + */ + public function fundAccount($accountId) + { + if ($accountId instanceof Keypair) { + $accountId = $accountId->getPublicKey(); + } + + try { + $this->apiClient->get(sprintf('/friendbot?addr=%s', $accountId)); + return true; + } + catch (HorizonException $e) { + // Account has already been funded + if ($e->getHttpStatusCode() == 400) { + return false; + } + + // Unexpected exception + throw $e; + } + + } + + /** + * Submits a base64-encoded transaction to the Stellar network. + * + * No additional validation is performed on this transaction + * + * @param $base64TransactionEnvelope + * @return Horizon\Api\HorizonResponse + */ + public function submitB64Transaction($base64TransactionEnvelope) + { + return $this->apiClient->submitB64Transaction($base64TransactionEnvelope); + } + + /** + * @return string + */ + public function getHorizonBaseUrl() + { + return $this->apiClient->getBaseUrl(); + } + + /** + * @return SigningInterface + */ + public function getSigningProvider() + { + return $this->signingProvider; + } + + /** + * @param SigningInterface $signingProvider + */ + public function setSigningProvider($signingProvider) + { + $this->signingProvider = $signingProvider; + } + + /** + * @return ApiClient + */ + public function getApiClient() + { + return $this->apiClient; + } + + /** + * @param ApiClient $apiClient + */ + public function setApiClient($apiClient) + { + $this->apiClient = $apiClient; + } +} diff --git a/src/Signing/PrivateKeySigner.php b/src/Signing/PrivateKeySigner.php index 70b6064..7a8d454 100644 --- a/src/Signing/PrivateKeySigner.php +++ b/src/Signing/PrivateKeySigner.php @@ -1,38 +1,38 @@ -keypair = $keypair; - } - - /** - * @param TransactionBuilder $builder - * @return DecoratedSignature - */ - public function signTransaction(TransactionBuilder $builder) - { - $hash = $builder - ->getTransactionEnvelope() - ->getHash(); - - return $this->keypair->signDecorated($hash); - } +keypair = $keypair; + } + + /** + * @param TransactionBuilder $builder + * @return DecoratedSignature + */ + public function signTransaction(TransactionBuilder $builder) + { + $hash = $builder + ->getTransactionEnvelope() + ->getHash(); + + return $this->keypair->signDecorated($hash); + } } \ No newline at end of file diff --git a/src/Signing/SigningInterface.php b/src/Signing/SigningInterface.php index 6d66245..c882464 100644 --- a/src/Signing/SigningInterface.php +++ b/src/Signing/SigningInterface.php @@ -1,18 +1,18 @@ -accountIndex = $accountIndex; - - $this->trezorBinPath = 'trezorctl'; - } - - public function signTransaction(TransactionBuilder $builder) - { - $xdr = $builder - ->getTransactionEnvelope() - ->toXdr(); - - $networkPassphrase = $builder->getApiClient()->getNetworkPassphrase(); - - $bip32Path = sprintf("m/44'/148'/%s'", $this->accountIndex); - - $cmd = sprintf('%s stellar_sign_transaction --address %s -n %s %s', - $this->trezorBinPath, - escapeshellarg($bip32Path), - escapeshellarg($networkPassphrase), - escapeshellarg(base64_encode($xdr)) - ); - - $output = []; - $retval = null; - $signatureb64 = exec($cmd, $output, $retval); - - // convert signature to raw bytes - $signatureBytes = base64_decode($signatureb64); - - // Convert to DecoratedSignature - $hint = substr($this->publickKeyBytes, -4); - return new DecoratedSignature($hint, $signatureBytes); - } - - public function setPublicKey(Keypair $keypair) - { - $this->publickKeyBytes = $keypair->getPublicKeyBytes(); - } - - /** - * @return string - */ - public function getTrezorBinPath() - { - return $this->trezorBinPath; - } - - /** - * @param string $trezorBinPath - */ - public function setTrezorBinPath($trezorBinPath) - { - $this->trezorBinPath = $trezorBinPath; - } +accountIndex = $accountIndex; + + $this->trezorBinPath = 'trezorctl'; + } + + public function signTransaction(TransactionBuilder $builder) + { + $xdr = $builder + ->getTransactionEnvelope() + ->toXdr(); + + $networkPassphrase = $builder->getApiClient()->getNetworkPassphrase(); + + $bip32Path = sprintf("m/44'/148'/%s'", $this->accountIndex); + + $cmd = sprintf('%s stellar_sign_transaction --address %s -n %s %s', + $this->trezorBinPath, + escapeshellarg($bip32Path), + escapeshellarg($networkPassphrase), + escapeshellarg(base64_encode($xdr)) + ); + + $output = []; + $retval = null; + $signatureb64 = exec($cmd, $output, $retval); + + // convert signature to raw bytes + $signatureBytes = base64_decode($signatureb64); + + // Convert to DecoratedSignature + $hint = substr($this->publickKeyBytes, -4); + return new DecoratedSignature($hint, $signatureBytes); + } + + public function setPublicKey(Keypair $keypair) + { + $this->publickKeyBytes = $keypair->getPublicKeyBytes(); + } + + /** + * @return string + */ + public function getTrezorBinPath() + { + return $this->trezorBinPath; + } + + /** + * @param string $trezorBinPath + */ + public function setTrezorBinPath($trezorBinPath) + { + $this->trezorBinPath = $trezorBinPath; + } } \ No newline at end of file diff --git a/src/Transaction/Transaction.php b/src/Transaction/Transaction.php index 0ca53db..a2a8efb 100644 --- a/src/Transaction/Transaction.php +++ b/src/Transaction/Transaction.php @@ -1,164 +1,164 @@ -sourceAccountId = AccountId::fromXdr($xdr); - $tx->feePaid = new StellarAmount($xdr->readUnsignedInteger()); - $tx->sequenceNumber = $xdr->readBigInteger(); - - // time bounds are optional - if ($xdr->readBoolean()) { - $tx->timeBounds = TimeBounds::fromXdr($xdr); - } - - $tx->memo = Memo::fromXdr($xdr); - - $numOperations = $xdr->readUnsignedInteger(); - for ($i=0; $i < $numOperations; $i++) { - $tx->operations[] = Operation::fromXdr($xdr); - } - - // 4 bytes at the end are reserved for future use - $xdr->readOpaqueFixed(4); - - return $tx; - } - - public function __construct() - { - $this->timeBounds = new TimeBounds(); - } - - /** - * @param Server $server - * @return TransactionBuilder - */ - public function toTransactionBuilder(Server $server = null) - { - $builder = new TransactionBuilder($this->sourceAccountId->getAccountIdString()); - - if ($server) { - $builder->setApiClient($server->getApiClient()); - } - - - $builder->setSequenceNumber($this->sequenceNumber); - - if (!$this->timeBounds->isEmpty()) { - $builder->setLowerTimebound($this->timeBounds->getMinTime()); - $builder->setUpperTimebound($this->timeBounds->getMaxTime()); - } - - $builder->setMemo($this->memo); - - foreach ($this->operations as $operation) { - $builder->addOperation($operation); - } - - return $builder; - } - - /** - * @return AccountId - */ - public function getSourceAccountId() - { - return $this->sourceAccountId; - } - - /** - * @return TimeBounds - */ - public function getTimeBounds() - { - return $this->timeBounds; - } - - /** - * @return Memo - */ - public function getMemo() - { - return $this->memo; - } - - /** - * @return Operation[] - */ - public function getOperations() - { - return $this->operations; - } - - /** - * @return BigInteger - */ - public function getSequenceNumber() - { - return $this->sequenceNumber; - } - - /** - * @return StellarAmount - */ - public function getFeePaid() - { - return $this->feePaid; - } +sourceAccountId = AccountId::fromXdr($xdr); + $tx->feePaid = new StellarAmount($xdr->readUnsignedInteger()); + $tx->sequenceNumber = $xdr->readBigInteger(); + + // time bounds are optional + if ($xdr->readBoolean()) { + $tx->timeBounds = TimeBounds::fromXdr($xdr); + } + + $tx->memo = Memo::fromXdr($xdr); + + $numOperations = $xdr->readUnsignedInteger(); + for ($i=0; $i < $numOperations; $i++) { + $tx->operations[] = Operation::fromXdr($xdr); + } + + // 4 bytes at the end are reserved for future use + $xdr->readOpaqueFixed(4); + + return $tx; + } + + public function __construct() + { + $this->timeBounds = new TimeBounds(); + } + + /** + * @param Server $server + * @return TransactionBuilder + */ + public function toTransactionBuilder(Server $server = null) + { + $builder = new TransactionBuilder($this->sourceAccountId->getAccountIdString()); + + if ($server) { + $builder->setApiClient($server->getApiClient()); + } + + + $builder->setSequenceNumber($this->sequenceNumber); + + if (!$this->timeBounds->isEmpty()) { + $builder->setLowerTimebound($this->timeBounds->getMinTime()); + $builder->setUpperTimebound($this->timeBounds->getMaxTime()); + } + + $builder->setMemo($this->memo); + + foreach ($this->operations as $operation) { + $builder->addOperation($operation); + } + + return $builder; + } + + /** + * @return AccountId + */ + public function getSourceAccountId() + { + return $this->sourceAccountId; + } + + /** + * @return TimeBounds + */ + public function getTimeBounds() + { + return $this->timeBounds; + } + + /** + * @return Memo + */ + public function getMemo() + { + return $this->memo; + } + + /** + * @return Operation[] + */ + public function getOperations() + { + return $this->operations; + } + + /** + * @return BigInteger + */ + public function getSequenceNumber() + { + return $this->sequenceNumber; + } + + /** + * @return StellarAmount + */ + public function getFeePaid() + { + return $this->feePaid; + } } \ No newline at end of file diff --git a/src/Transaction/TransactionBuilder.php b/src/Transaction/TransactionBuilder.php index 6b6f84a..c0a60a9 100755 --- a/src/Transaction/TransactionBuilder.php +++ b/src/Transaction/TransactionBuilder.php @@ -1,608 +1,608 @@ -accountId = new AccountId($sourceAccountId); - - $this->timeBounds = new TimeBounds(); - $this->memo = new Memo(Memo::MEMO_TYPE_NONE); - $this->operations = new VariableArray(); - - $this->signatures = []; - - return $this; - } - - /** - * Uses $signer to add a new DecoratedSignature to this TransactionBuilder - * - * @param SigningInterface $signer - * @return DecoratedSignature - */ - public function signWith(SigningInterface $signer) - { - $decoratedSignature = $signer->signTransaction($this); - - $this->signatures[] = $decoratedSignature; - - return $decoratedSignature; - } - - /** - * @param Keypair $keypair - * @return DecoratedSignature - */ - public function getSignatureForKeypair(Keypair $keypair) - { - $signer = new PrivateKeySigner($keypair); - - return $this->signWith($signer); - } - - /** - * @return TransactionEnvelope - */ - public function getTransactionEnvelope() - { - $txEnvelope = new TransactionEnvelope($this); - - foreach ($this->signatures as $signature) { - $txEnvelope->addDecoratedSignature($signature); - } - - return $txEnvelope; - } - - /** - * @param $secretKeyString - * @return TransactionEnvelope - */ - public function sign($secretKeyString = null) - { - if ($secretKeyString instanceof Keypair) { - $secretKeyString = $secretKeyString->getSecret(); - } - - // If $secretKeyString is null, check for a SigningProvider - if (!$secretKeyString) { - // No secret key and no signing provider: could be a pre-authorized - // transaction. Return empty envelope with no signatures - if (!$this->signingProvider) { - return new TransactionEnvelope($this); - } - - $this->signWith($this->signingProvider); - - return $this->getTransactionEnvelope(); - } - else { - return (new TransactionEnvelope($this))->sign($secretKeyString); - } - } - - public function hash() - { - return $this->apiClient->hash($this); - } - - public function getHashAsString() - { - return $this->apiClient->getHashAsString($this); - } - - /** - * @param $secretKeyString string|Keypair - * @return PostTransactionResponse - * @throws PostTransactionException - * @throws \ErrorException - */ - public function submit($secretKeyString = null) - { - if ($secretKeyString instanceof Keypair) { - $secretKeyString = $secretKeyString->getSecret(); - } - - return $this->apiClient->submitTransaction($this, $secretKeyString); - } - - public function getFee() - { - // todo: load base fee from network - return 100 * $this->operations->count(); - } - - /** - * @param string|Keypair $destination - * @param number|BigInteger $amount int representing lumens or BigInteger representing stroops - * @param null $sourceAccountId - * @return TransactionBuilder - */ - public function addLumenPayment($destination, $amount, $sourceAccountId = null) - { - return $this->addOperation(PaymentOp::newNativePayment($destination, $amount, $sourceAccountId)); - } - - /** - * @param string $newAccountId - * @param number|BigInteger $amount int representing lumens or BigInteger representing stroops - * @param string $sourceAccountId - * @return TransactionBuilder - */ - public function addCreateAccountOp($newAccountId, $amount, $sourceAccountId = null) - { - return $this->addOperation(new CreateAccountOp(new AccountId($newAccountId), $amount, $sourceAccountId)); - } - - /** - * @param Asset $asset - * @param number|BigInteger $amount number representing lumens or BigInteger representing stroops - * @param string|Keypair $destinationAccountId - * $param null|string|Keypair $sourceAccountId - * @return TransactionBuilder - */ - public function addCustomAssetPaymentOp(Asset $asset, $amount, $destinationAccountId, $sourceAccountId = null) - { - return $this->addOperation( - PaymentOp::newCustomPayment($destinationAccountId, $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString(), $sourceAccountId) - ); - } - - /** - * @param Asset $asset - * @param int $amount defaults to maximum if null - * @param null $sourceAccountId - * @return TransactionBuilder - */ - public function addChangeTrustOp(Asset $asset, $amount = null, $sourceAccountId = null) - { - if ($amount === null) { - $amount = StellarAmount::newMaximum(); - } - - return $this->addOperation(new ChangeTrustOp($asset, $amount, $sourceAccountId)); - } - - /** - * This is called by asset issuers to authorize a trustline established by - * a client account - * - * @param Asset $asset - * @param $trustorId - * @param null $sourceAccountId - * @return TransactionBuilder - */ - public function authorizeTrustline(Asset $asset, $trustorId, $sourceAccountId = null) - { - if ($trustorId instanceof Keypair) { - $trustorId = $trustorId->getPublicKey(); - } - - $op = new AllowTrustOp($asset, new AccountId($trustorId), $sourceAccountId); - $op->setIsAuthorized(true); - - return $this->addOperation($op); - } - - /** - * This is called by asset issuers to revoke a trustline established by - * a client account - * - * @param Asset $asset - * @param $trustorId - * @param null $sourceAccountId - * @return TransactionBuilder - */ - public function revokeTrustline(Asset $asset, $trustorId, $sourceAccountId = null) - { - if ($trustorId instanceof Keypair) { - $trustorId = $trustorId->getPublicKey(); - } - - $op = new AllowTrustOp($asset, new AccountId($trustorId), $sourceAccountId); - $op->setIsAuthorized(false); - - return $this->addOperation($op); - } - - /** - * Adds an operation to merge the balance of the source account to $destinationAccountId - * @param $destinationAccountId - * @param null $sourceAccountId - * @return TransactionBuilder - */ - public function addMergeOperation($destinationAccountId, $sourceAccountId = null) - { - if ($destinationAccountId instanceof Keypair) { - $destinationAccountId = $destinationAccountId->getPublicKey(); - } - - return $this->addOperation(new AccountMergeOp($destinationAccountId, $sourceAccountId)); - } - - /** - * @param $key - * @param $value - * @param null $sourceAccountId - * @return TransactionBuilder - */ - public function setAccountData($key, $value = null, $sourceAccountId = null) - { - return $this->addOperation(new ManageDataOp($key, $value, $sourceAccountId)); - } - - /** - * @param $key - * @param null $sourceAccountId - * @return TransactionBuilder - */ - public function clearAccountData($key, $sourceAccountId = null) - { - return $this->addOperation(new ManageDataOp($key, null, $sourceAccountId)); - } - - /** - * @param BigInteger $bumpTo - * @param null $sourceAccountId - * @return TransactionBuilder - */ - public function bumpSequenceTo(BigInteger $bumpTo, $sourceAccountId = null) - { - return $this->addOperation(new BumpSequenceOp($bumpTo, $sourceAccountId)); - } - - /** - * @return string - */ - public function toXdr() - { - $bytes = ''; - - if (!$this->sequenceNumber) { - $this->sequenceNumber = $this->generateSequenceNumber(); - } - - // Account ID (36 bytes) - $bytes .= $this->accountId->toXdr(); - // Fee (4 bytes) - $bytes .= XdrEncoder::unsignedInteger($this->getFee()); - // Sequence number (8 bytes) - $bytes .= XdrEncoder::unsignedBigInteger64($this->sequenceNumber); - - // Time Bounds are optional - if ($this->timeBounds->isEmpty()) { - $bytes .= XdrEncoder::boolean(false); - } - else { - $bytes .= XdrEncoder::boolean(true); - $bytes .= $this->timeBounds->toXdr(); - } - - // Memo (4 bytes if empty, 36 bytes maximum) - $bytes .= $this->memo->toXdr(); - - // Operations - $bytes .= $this->operations->toXdr(); - - // TransactionExt (union reserved for future use) - $bytes .= XdrEncoder::unsignedInteger(0); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @param Server $server - * @return TransactionBuilder - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr, Server $server) - { - return Transaction::fromXdr($xdr)->toTransactionBuilder($server); - } - - /** - * @param $operation - * @return TransactionBuilder - */ - public function addOperation($operation) - { - $this->operations->append($operation); - - return $this; - } - - /** - * @param $memo - * @return $this - */ - public function setTextMemo($memo) - { - $this->memo = new Memo(Memo::MEMO_TYPE_TEXT, $memo); - - return $this; - } - - /** - * @param $memo - * @return $this - */ - public function setIdMemo($memo) - { - $this->memo = new Memo(Memo::MEMO_TYPE_ID, $memo); - - return $this; - } - - /** - * Note: this should be called with the raw sha256 hash - * - * For example: - * $builder->setHashMemo(hash('sha256', 'example thing being hashed', true)); - * - * @param $memo 32-byte sha256 hash - * @return $this - */ - public function setHashMemo($memo) - { - $this->memo = new Memo(Memo::MEMO_TYPE_HASH, $memo); - - return $this; - } - - /** - * Note: this should be called with the raw sha256 hash - * - * For example: - * $builder->setReturnMemo(hash('sha256', 'example thing being hashed', true)); - * - * @param $memo 32-byte sha256 hash - * @return $this - */ - public function setReturnMemo($memo) - { - $this->memo = new Memo(Memo::MEMO_TYPE_RETURN, $memo); - - return $this; - } - - /** - * @param \DateTime $lowerTimebound - * @return $this - */ - public function setLowerTimebound(\DateTime $lowerTimebound) - { - $this->timeBounds->setMinTime($lowerTimebound); - - return $this; - } - - /** - * @param \DateTime $upperTimebound - * @return $this - */ - public function setUpperTimebound(\DateTime $upperTimebound) - { - $this->timeBounds->setMaxTime($upperTimebound); - - return $this; - } - - protected function generateSequenceNumber() - { - $this->ensureApiClient(); - - $account = $this->apiClient - ->getAccount($this->accountId->getAccountIdString()); - - if (!$account) { - throw new \ErrorException(sprintf('Account not found: %s', $this->accountId->getAccountIdString())); - } - - return $account->getSequenceAsBigInteger()->add(new BigInteger(1)); - } - - protected function ensureApiClient() - { - if (!$this->apiClient) throw new \ErrorException("An API client is required, call setApiClient before using this method"); - } - - /** - * @return ApiClient - */ - public function getApiClient() - { - return $this->apiClient; - } - - /** - * @param ApiClient $apiClient - * @return TransactionBuilder - */ - public function setApiClient($apiClient) - { - $this->apiClient = $apiClient; - - return $this; - } - - /** - * @return SigningInterface - */ - public function getSigningProvider() - { - return $this->signingProvider; - } - - /** - * @param SigningInterface $signingProvider - */ - public function setSigningProvider($signingProvider) - { - $this->signingProvider = $signingProvider; - - return $this; - } - - /** - * @return BigInteger - */ - public function getSequenceNumber() - { - return $this->sequenceNumber; - } - - /** - * @param BigInteger $sequenceNumber - */ - public function setSequenceNumber($sequenceNumber) - { - if (!is_a($sequenceNumber, 'phpseclib\Math\BigInteger')) { - $sequenceNumber = new BigInteger($sequenceNumber); - } - - $this->sequenceNumber = $sequenceNumber; - - return $this; - } - - /** - * @return Memo - */ - public function getMemo() - { - return $this->memo; - } - - /** - * @param Memo $memo - */ - public function setMemo($memo) - { - $this->memo = $memo; - - return $this; - } +accountId = new AccountId($sourceAccountId); + + $this->timeBounds = new TimeBounds(); + $this->memo = new Memo(Memo::MEMO_TYPE_NONE); + $this->operations = new VariableArray(); + + $this->signatures = []; + + return $this; + } + + /** + * Uses $signer to add a new DecoratedSignature to this TransactionBuilder + * + * @param SigningInterface $signer + * @return DecoratedSignature + */ + public function signWith(SigningInterface $signer) + { + $decoratedSignature = $signer->signTransaction($this); + + $this->signatures[] = $decoratedSignature; + + return $decoratedSignature; + } + + /** + * @param Keypair $keypair + * @return DecoratedSignature + */ + public function getSignatureForKeypair(Keypair $keypair) + { + $signer = new PrivateKeySigner($keypair); + + return $this->signWith($signer); + } + + /** + * @return TransactionEnvelope + */ + public function getTransactionEnvelope() + { + $txEnvelope = new TransactionEnvelope($this); + + foreach ($this->signatures as $signature) { + $txEnvelope->addDecoratedSignature($signature); + } + + return $txEnvelope; + } + + /** + * @param $secretKeyString + * @return TransactionEnvelope + */ + public function sign($secretKeyString = null) + { + if ($secretKeyString instanceof Keypair) { + $secretKeyString = $secretKeyString->getSecret(); + } + + // If $secretKeyString is null, check for a SigningProvider + if (!$secretKeyString) { + // No secret key and no signing provider: could be a pre-authorized + // transaction. Return empty envelope with no signatures + if (!$this->signingProvider) { + return new TransactionEnvelope($this); + } + + $this->signWith($this->signingProvider); + + return $this->getTransactionEnvelope(); + } + else { + return (new TransactionEnvelope($this))->sign($secretKeyString); + } + } + + public function hash() + { + return $this->apiClient->hash($this); + } + + public function getHashAsString() + { + return $this->apiClient->getHashAsString($this); + } + + /** + * @param $secretKeyString string|Keypair + * @return PostTransactionResponse + * @throws PostTransactionException + * @throws \ErrorException + */ + public function submit($secretKeyString = null) + { + if ($secretKeyString instanceof Keypair) { + $secretKeyString = $secretKeyString->getSecret(); + } + + return $this->apiClient->submitTransaction($this, $secretKeyString); + } + + public function getFee() + { + // todo: load base fee from network + return 100 * $this->operations->count(); + } + + /** + * @param string|Keypair $destination + * @param number|BigInteger $amount int representing lumens or BigInteger representing stroops + * @param null $sourceAccountId + * @return TransactionBuilder + */ + public function addLumenPayment($destination, $amount, $sourceAccountId = null) + { + return $this->addOperation(PaymentOp::newNativePayment($destination, $amount, $sourceAccountId)); + } + + /** + * @param string $newAccountId + * @param number|BigInteger $amount int representing lumens or BigInteger representing stroops + * @param string $sourceAccountId + * @return TransactionBuilder + */ + public function addCreateAccountOp($newAccountId, $amount, $sourceAccountId = null) + { + return $this->addOperation(new CreateAccountOp(new AccountId($newAccountId), $amount, $sourceAccountId)); + } + + /** + * @param Asset $asset + * @param number|BigInteger $amount number representing lumens or BigInteger representing stroops + * @param string|Keypair $destinationAccountId + * $param null|string|Keypair $sourceAccountId + * @return TransactionBuilder + */ + public function addCustomAssetPaymentOp(Asset $asset, $amount, $destinationAccountId, $sourceAccountId = null) + { + return $this->addOperation( + PaymentOp::newCustomPayment($destinationAccountId, $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString(), $sourceAccountId) + ); + } + + /** + * @param Asset $asset + * @param int $amount defaults to maximum if null + * @param null $sourceAccountId + * @return TransactionBuilder + */ + public function addChangeTrustOp(Asset $asset, $amount = null, $sourceAccountId = null) + { + if ($amount === null) { + $amount = StellarAmount::newMaximum(); + } + + return $this->addOperation(new ChangeTrustOp($asset, $amount, $sourceAccountId)); + } + + /** + * This is called by asset issuers to authorize a trustline established by + * a client account + * + * @param Asset $asset + * @param $trustorId + * @param null $sourceAccountId + * @return TransactionBuilder + */ + public function authorizeTrustline(Asset $asset, $trustorId, $sourceAccountId = null) + { + if ($trustorId instanceof Keypair) { + $trustorId = $trustorId->getPublicKey(); + } + + $op = new AllowTrustOp($asset, new AccountId($trustorId), $sourceAccountId); + $op->setIsAuthorized(true); + + return $this->addOperation($op); + } + + /** + * This is called by asset issuers to revoke a trustline established by + * a client account + * + * @param Asset $asset + * @param $trustorId + * @param null $sourceAccountId + * @return TransactionBuilder + */ + public function revokeTrustline(Asset $asset, $trustorId, $sourceAccountId = null) + { + if ($trustorId instanceof Keypair) { + $trustorId = $trustorId->getPublicKey(); + } + + $op = new AllowTrustOp($asset, new AccountId($trustorId), $sourceAccountId); + $op->setIsAuthorized(false); + + return $this->addOperation($op); + } + + /** + * Adds an operation to merge the balance of the source account to $destinationAccountId + * @param $destinationAccountId + * @param null $sourceAccountId + * @return TransactionBuilder + */ + public function addMergeOperation($destinationAccountId, $sourceAccountId = null) + { + if ($destinationAccountId instanceof Keypair) { + $destinationAccountId = $destinationAccountId->getPublicKey(); + } + + return $this->addOperation(new AccountMergeOp($destinationAccountId, $sourceAccountId)); + } + + /** + * @param $key + * @param $value + * @param null $sourceAccountId + * @return TransactionBuilder + */ + public function setAccountData($key, $value = null, $sourceAccountId = null) + { + return $this->addOperation(new ManageDataOp($key, $value, $sourceAccountId)); + } + + /** + * @param $key + * @param null $sourceAccountId + * @return TransactionBuilder + */ + public function clearAccountData($key, $sourceAccountId = null) + { + return $this->addOperation(new ManageDataOp($key, null, $sourceAccountId)); + } + + /** + * @param BigInteger $bumpTo + * @param null $sourceAccountId + * @return TransactionBuilder + */ + public function bumpSequenceTo(BigInteger $bumpTo, $sourceAccountId = null) + { + return $this->addOperation(new BumpSequenceOp($bumpTo, $sourceAccountId)); + } + + /** + * @return string + */ + public function toXdr() + { + $bytes = ''; + + if (!$this->sequenceNumber) { + $this->sequenceNumber = $this->generateSequenceNumber(); + } + + // Account ID (36 bytes) + $bytes .= $this->accountId->toXdr(); + // Fee (4 bytes) + $bytes .= XdrEncoder::unsignedInteger($this->getFee()); + // Sequence number (8 bytes) + $bytes .= XdrEncoder::unsignedBigInteger64($this->sequenceNumber); + + // Time Bounds are optional + if ($this->timeBounds->isEmpty()) { + $bytes .= XdrEncoder::boolean(false); + } + else { + $bytes .= XdrEncoder::boolean(true); + $bytes .= $this->timeBounds->toXdr(); + } + + // Memo (4 bytes if empty, 36 bytes maximum) + $bytes .= $this->memo->toXdr(); + + // Operations + $bytes .= $this->operations->toXdr(); + + // TransactionExt (union reserved for future use) + $bytes .= XdrEncoder::unsignedInteger(0); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @param Server $server + * @return TransactionBuilder + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr, Server $server) + { + return Transaction::fromXdr($xdr)->toTransactionBuilder($server); + } + + /** + * @param $operation + * @return TransactionBuilder + */ + public function addOperation($operation) + { + $this->operations->append($operation); + + return $this; + } + + /** + * @param $memo + * @return $this + */ + public function setTextMemo($memo) + { + $this->memo = new Memo(Memo::MEMO_TYPE_TEXT, $memo); + + return $this; + } + + /** + * @param $memo + * @return $this + */ + public function setIdMemo($memo) + { + $this->memo = new Memo(Memo::MEMO_TYPE_ID, $memo); + + return $this; + } + + /** + * Note: this should be called with the raw sha256 hash + * + * For example: + * $builder->setHashMemo(hash('sha256', 'example thing being hashed', true)); + * + * @param $memo 32-byte sha256 hash + * @return $this + */ + public function setHashMemo($memo) + { + $this->memo = new Memo(Memo::MEMO_TYPE_HASH, $memo); + + return $this; + } + + /** + * Note: this should be called with the raw sha256 hash + * + * For example: + * $builder->setReturnMemo(hash('sha256', 'example thing being hashed', true)); + * + * @param $memo 32-byte sha256 hash + * @return $this + */ + public function setReturnMemo($memo) + { + $this->memo = new Memo(Memo::MEMO_TYPE_RETURN, $memo); + + return $this; + } + + /** + * @param \DateTime $lowerTimebound + * @return $this + */ + public function setLowerTimebound(\DateTime $lowerTimebound) + { + $this->timeBounds->setMinTime($lowerTimebound); + + return $this; + } + + /** + * @param \DateTime $upperTimebound + * @return $this + */ + public function setUpperTimebound(\DateTime $upperTimebound) + { + $this->timeBounds->setMaxTime($upperTimebound); + + return $this; + } + + protected function generateSequenceNumber() + { + $this->ensureApiClient(); + + $account = $this->apiClient + ->getAccount($this->accountId->getAccountIdString()); + + if (!$account) { + throw new \ErrorException(sprintf('Account not found: %s', $this->accountId->getAccountIdString())); + } + + return $account->getSequenceAsBigInteger()->add(new BigInteger(1)); + } + + protected function ensureApiClient() + { + if (!$this->apiClient) throw new \ErrorException("An API client is required, call setApiClient before using this method"); + } + + /** + * @return ApiClient + */ + public function getApiClient() + { + return $this->apiClient; + } + + /** + * @param ApiClient $apiClient + * @return TransactionBuilder + */ + public function setApiClient($apiClient) + { + $this->apiClient = $apiClient; + + return $this; + } + + /** + * @return SigningInterface + */ + public function getSigningProvider() + { + return $this->signingProvider; + } + + /** + * @param SigningInterface $signingProvider + */ + public function setSigningProvider($signingProvider) + { + $this->signingProvider = $signingProvider; + + return $this; + } + + /** + * @return BigInteger + */ + public function getSequenceNumber() + { + return $this->sequenceNumber; + } + + /** + * @param BigInteger $sequenceNumber + */ + public function setSequenceNumber($sequenceNumber) + { + if (!is_a($sequenceNumber, 'phpseclib3\Math\BigInteger')) { + $sequenceNumber = new BigInteger($sequenceNumber); + } + + $this->sequenceNumber = $sequenceNumber; + + return $this; + } + + /** + * @return Memo + */ + public function getMemo() + { + return $this->memo; + } + + /** + * @param Memo $memo + */ + public function setMemo($memo) + { + $this->memo = $memo; + + return $this; + } } \ No newline at end of file diff --git a/src/Util/Checksum.php b/src/Util/Checksum.php index 220fcf2..a99e050 100755 --- a/src/Util/Checksum.php +++ b/src/Util/Checksum.php @@ -1,61 +1,61 @@ -> (7 - $i) & 1) == 1); - $c15 = (($crc >> 15 & 1) == 1); - $crc <<= 1; - if ($c15 ^ $bit) $crc ^= $polynomial; - } - } - - return $crc & 0xffff; - } +> (7 - $i) & 1) == 1); + $c15 = (($crc >> 15 & 1) == 1); + $crc <<= 1; + if ($c15 ^ $bit) $crc ^= $polynomial; + } + } + + return $crc & 0xffff; + } } \ No newline at end of file diff --git a/src/Util/Debug.php b/src/Util/Debug.php index 643f847..b26de34 100755 --- a/src/Util/Debug.php +++ b/src/Util/Debug.php @@ -1,51 +1,51 @@ -= 0x20 && $i <= 0x7E) ? chr($i) : $pad; - } - } - - $hex = str_split(bin2hex($data), $width*2); - $chars = str_split(strtr($data, $from, $to), $width); - - $offset = 0; - foreach ($hex as $i => $line) - { - $output .= sprintf('%6X',$offset).' : '.implode(' ', str_split($line,2)) . ' [' . $chars[$i] . ']' . $newline; - $offset += $width; - } - - return $output; - } += 0x20 && $i <= 0x7E) ? chr($i) : $pad; + } + } + + $hex = str_split(bin2hex($data), $width*2); + $chars = str_split(strtr($data, $from, $to), $width); + + $offset = 0; + foreach ($hex as $i => $line) + { + $output .= sprintf('%6X',$offset).' : '.implode(' ', str_split($line,2)) . ' [' . $chars[$i] . ']' . $newline; + $offset += $width; + } + + return $output; + } } \ No newline at end of file diff --git a/src/Util/Hash.php b/src/Util/Hash.php index b018ede..62d2d3e 100755 --- a/src/Util/Hash.php +++ b/src/Util/Hash.php @@ -1,30 +1,30 @@ -elements = []; - } - - public function append(XdrEncodableInterface $element) - { - $this->elements[] = $element; - } - - public function toXdr() - { - $bytes = ''; - - if (count($this->elements) > (pow(2, 32) - 1)) { - throw new \ErrorException('Maximum number of elements exceeded'); - } - - $bytes .= XdrEncoder::unsignedInteger(count($this->elements)); - - foreach ($this->elements as $element) { - $bytes .= $element->toXdr(); - } - - return $bytes; - } - - /** - * @return int - */ - public function count() +elements = []; + } + + public function append(XdrEncodableInterface $element) + { + $this->elements[] = $element; + } + + public function toXdr() + { + $bytes = ''; + + if (count($this->elements) > (pow(2, 32) - 1)) { + throw new \ErrorException('Maximum number of elements exceeded'); + } + + $bytes .= XdrEncoder::unsignedInteger(count($this->elements)); + + foreach ($this->elements as $element) { + $bytes .= $element->toXdr(); + } + + return $bytes; + } + + /** + * @return int + */ + public function count(): int { return count($this->elements); } - - /** - * @return array - */ - public function toArray() - { - return array_values($this->elements); - } -} \ No newline at end of file + + /** + * @return array + */ + public function toArray() + { + return array_values($this->elements); + } +} diff --git a/src/Xdr/XdrBuffer.php b/src/Xdr/XdrBuffer.php index e26d94b..e076e61 100644 --- a/src/Xdr/XdrBuffer.php +++ b/src/Xdr/XdrBuffer.php @@ -1,218 +1,225 @@ -xdrBytes = $xdrBytes; - - $this->position = 0; - $this->size = strlen($xdrBytes); - } - - /** - * @return int - * @throws \ErrorException - */ - public function readUnsignedInteger() - { - $dataSize = 4; - $this->assertBytesRemaining($dataSize); - - $data = XdrDecoder::unsignedInteger(substr($this->xdrBytes, $this->position, $dataSize)); - $this->position += $dataSize; - - return $data; - } - - /** - * @return int - * @throws \ErrorException - */ - public function readUnsignedInteger64() - { - $dataSize = 8; - $this->assertBytesRemaining($dataSize); - - $data = XdrDecoder::unsignedInteger64(substr($this->xdrBytes, $this->position, $dataSize)); - $this->position += $dataSize; - - return $data; - } - - /** - * @return BigInteger - * @throws \ErrorException - */ - public function readBigInteger() - { - $dataSize = 8; - $this->assertBytesRemaining($dataSize); - - $bigInteger = new BigInteger(substr($this->xdrBytes, $this->position, $dataSize), 256); - $this->position += $dataSize; - - return $bigInteger; - } - - /** - * @return int - * @throws \ErrorException - */ - public function readInteger() - { - $dataSize = 4; - $this->assertBytesRemaining($dataSize); - - $data = XdrDecoder::signedInteger(substr($this->xdrBytes, $this->position, $dataSize)); - $this->position += $dataSize; - - return $data; - } - - /** - * @return int - * @throws \ErrorException - */ - public function readInteger64() - { - $dataSize = 8; - $this->assertBytesRemaining($dataSize); - - $data = XdrDecoder::signedInteger64(substr($this->xdrBytes, $this->position, $dataSize)); - $this->position += $dataSize; - - return $data; - } - - /** - * @param $length - * @return bool|string - * @throws \ErrorException - */ - public function readOpaqueFixed($length) - { - $this->assertBytesRemaining($length); - - $data = XdrDecoder::opaqueFixed(substr($this->xdrBytes, $this->position), $length); - $this->position += $length; - - return $data; - } - - /** - * @param $length - * @return string - * @throws \ErrorException - */ - public function readOpaqueFixedString($length) - { - $this->assertBytesRemaining($length); - - $data = XdrDecoder::opaqueFixedString(substr($this->xdrBytes, $this->position), $length); - $this->position += $length; - - return $data; - } - /** - * @return bool|string - * @throws \ErrorException - */ - public function readOpaqueVariable($maxLength = null) - { - $length = $this->readUnsignedInteger(); - $paddedLength = $this->roundTo4($length); - - if ($maxLength !== null && $length > $maxLength) { - throw new \InvalidArgumentException(sprintf('length of %s exceeds max length of %s', $length, $maxLength)); - } - - $this->assertBytesRemaining($paddedLength); - - $data = XdrDecoder::opaqueFixed(substr($this->xdrBytes, $this->position), $length); - $this->position += $paddedLength; - - return $data; - } - - /** - * @param null $maxLength - * @return bool|string - * @throws \ErrorException - */ - public function readString($maxLength = null) - { - $strLen = $this->readUnsignedInteger(); - $paddedLength = $this->roundTo4($strLen); - if ($strLen > $maxLength) throw new \InvalidArgumentException(sprintf('maxLength of %s exceeded (string is %s bytes)', $maxLength, $strLen)); - - $this->assertBytesRemaining($paddedLength); - - $data = XdrDecoder::opaqueFixed(substr($this->xdrBytes, $this->position), $strLen); - $this->position += $paddedLength; - - return $data; - } - - /** - * @return bool - * @throws \ErrorException - */ - public function readBoolean() - { - $dataSize = 4; - $this->assertBytesRemaining($dataSize); - - $data = XdrDecoder::boolean(substr($this->xdrBytes, $this->position, $dataSize)); - $this->position += $dataSize; - - return $data; - } - - /** - * @param $numBytes - * @throws \ErrorException - */ - protected function assertBytesRemaining($numBytes) - { - if ($this->position + $numBytes > $this->size) { - throw new \ErrorException('Unexpected end of XDR data'); - } - } - - /** - * rounds $number up to the nearest value that's a multiple of 4 + * Total size of the XDR byte buffer * - * @param $number - * @return int + * @var int */ - protected function roundTo4($number) - { - $remainder = $number % 4; - if (!$remainder) return $number; - - return $number + (4 - $remainder); - } -} \ No newline at end of file + protected $size; + + public function __construct($xdrBytes) + { + $this->xdrBytes = $xdrBytes; + + $this->position = 0; + $this->size = strlen($xdrBytes); + } + + /** + * @return int + * @throws \ErrorException + */ + public function readUnsignedInteger() + { + $dataSize = 4; + $this->assertBytesRemaining($dataSize); + + $data = XdrDecoder::unsignedInteger(substr($this->xdrBytes, $this->position, $dataSize)); + $this->position += $dataSize; + + return $data; + } + + /** + * @return int + * @throws \ErrorException + */ + public function readUnsignedInteger64() + { + $dataSize = 8; + $this->assertBytesRemaining($dataSize); + + $data = XdrDecoder::unsignedInteger64(substr($this->xdrBytes, $this->position, $dataSize)); + $this->position += $dataSize; + + return $data; + } + + /** + * @return BigInteger + * @throws \ErrorException + */ + public function readBigInteger() + { + $dataSize = 8; + $this->assertBytesRemaining($dataSize); + + $bigInteger = new BigInteger(substr($this->xdrBytes, $this->position, $dataSize), 256); + $this->position += $dataSize; + + return $bigInteger; + } + + /** + * @return int + * @throws \ErrorException + */ + public function readInteger() + { + $dataSize = 4; + $this->assertBytesRemaining($dataSize); + + $data = XdrDecoder::signedInteger(substr($this->xdrBytes, $this->position, $dataSize)); + $this->position += $dataSize; + + return $data; + } + + /** + * @return int + * @throws \ErrorException + */ + public function readInteger64() + { + $dataSize = 8; + $this->assertBytesRemaining($dataSize); + + $data = XdrDecoder::signedInteger64(substr($this->xdrBytes, $this->position, $dataSize)); + $this->position += $dataSize; + + return $data; + } + + /** + * @param $length + * @return bool|string + * @throws \ErrorException + */ + public function readOpaqueFixed($length) + { + $this->assertBytesRemaining($length); + + $data = XdrDecoder::opaqueFixed(substr($this->xdrBytes, $this->position), $length); + $this->position += $length; + + return $data; + } + + /** + * @param $length + * @return string + * @throws \ErrorException + */ + public function readOpaqueFixedString($length) + { + $this->assertBytesRemaining($length); + + $data = XdrDecoder::opaqueFixedString(substr($this->xdrBytes, $this->position), $length); + $this->position += $length; + + return $data; + } + + /** + * @return bool|string + * @throws \ErrorException + */ + public function readOpaqueVariable($maxLength = null) + { + $length = $this->readUnsignedInteger(); + $paddedLength = $this->roundTo4($length); + + if ($maxLength !== null && $length > $maxLength) { + throw new \InvalidArgumentException(sprintf('length of %s exceeds max length of %s', $length, $maxLength)); + } + + $this->assertBytesRemaining($paddedLength); + + $data = XdrDecoder::opaqueFixed(substr($this->xdrBytes, $this->position), $length); + $this->position += $paddedLength; + + return $data; + } + + /** + * @param null $maxLength + * @return bool|string + * @throws \ErrorException + */ + public function readString($maxLength = null) + { + $strLen = $this->readUnsignedInteger(); + $paddedLength = $this->roundTo4($strLen); + if ($strLen > $maxLength) throw new \InvalidArgumentException(sprintf('maxLength of %s exceeded (string is %s bytes)', $maxLength, $strLen)); + + $this->assertBytesRemaining($paddedLength); + + $data = XdrDecoder::opaqueFixed(substr($this->xdrBytes, $this->position), $strLen); + $this->position += $paddedLength; + + return $data; + } + + /** + * @return bool + * @throws \ErrorException + */ + public function readBoolean() + { + $dataSize = 4; + $this->assertBytesRemaining($dataSize); + + $data = XdrDecoder::boolean(substr($this->xdrBytes, $this->position, $dataSize)); + $this->position += $dataSize; + + return $data; + } + + /** + * @param $numBytes + * @throws \ErrorException + */ + protected function assertBytesRemaining($numBytes) + { + if ($this->position + $numBytes > $this->size) { + throw new \ErrorException('Unexpected end of XDR data'); + } + } + + /** + * rounds $number up to the nearest value that's a multiple of 4 + * + * @param $number + * @return int + */ + protected function roundTo4($number) + { + $remainder = $number % 4; + if (!$remainder) return $number; + + return $number + (4 - $remainder); + } +} diff --git a/src/Xdr/XdrDecoder.php b/src/Xdr/XdrDecoder.php index a314a7e..e3d4e4c 100644 --- a/src/Xdr/XdrDecoder.php +++ b/src/Xdr/XdrDecoder.php @@ -1,176 +1,176 @@ - $expectedLength) throw new \InvalidArgumentException(sprintf('Unexpected length for value. Has length %s, expected %s', strlen($value), $expectedLength)); - if ($expectedLength && !$padUnexpectedLength && strlen($value) != $expectedLength) throw new \InvalidArgumentException(sprintf('Unexpected length for value. Has length %s, expected %s', strlen($value), $expectedLength)); - - if ($expectedLength && strlen($value) != $expectedLength) { - $value = self::applyPadding($value, $expectedLength); - } - - return self::applyPadding($value); - } - - /** - * Variable-length opaque data - * - * Maximum length is 2^32 - 1 - * - * @param $value - * @return string - */ - public static function opaqueVariable($value) - { - $maxLength = pow(2, 32) - 1; - if (strlen($value) > $maxLength) throw new \InvalidArgumentException(sprintf('Value of length %s is greater than the maximum allowed length of %s', strlen($value), $maxLength)); - - $bytes = ''; - - $bytes .= self::unsignedInteger(strlen($value)); - $bytes .= self::applyPadding($value); - - return $bytes; - } - - public static function signedInteger($value) - { - // pack() does not support a signed 32-byte int, so work around this with - // custom encoding - return (self::nativeIsBigEndian()) ? pack('l', $value) : strrev(pack('l', $value)); - } - - public static function unsignedInteger($value) - { - // unsigned 32-bit big-endian - return pack('N', $value); - } - - public static function signedInteger64($value) - { - // pack() does not support a signed 64-byte int, so work around this with - // custom encoding - return (self::nativeIsBigEndian()) ? pack('q', $value) : strrev(pack('q', $value)); - } - - /** - * Converts $value to a signed 8-byte big endian int64 - * - * @param BigInteger $value - * @return string - */ - public static function signedBigInteger64(BigInteger $value) - { - $xdrBytes = ''; - $bigIntBytes = $value->toBytes(true); - $bigIntBits = $value->toBits(true); - - // Special case: MAX_UINT_64 will look like 00ffffffffffffffff and have an - // extra preceeding byte we need to get rid of - if (strlen($bigIntBytes) === 9 && substr($value->toHex(true), 0, 2) === '00') { - $bigIntBytes = substr($bigIntBytes, 1); - } - - $paddingChar = chr(0); - // If the number is negative, pad with 0xFF - if (substr($bigIntBits, 0, 1) == 1) { - $paddingChar = chr(255); - } - - $paddingBytes = 8 - strlen($bigIntBytes); - while ($paddingBytes > 0) { - $xdrBytes .= $paddingChar; - $paddingBytes--; - } - - $xdrBytes .= $bigIntBytes; - - return XdrEncoder::opaqueFixed($xdrBytes, 8); - } - - /** - * Converts $value to an unsigned 8-byte big endian uint64 - * - * @param BigInteger $value - * @return string - */ - public static function unsignedBigInteger64(BigInteger $value) - { - $xdrBytes = ''; - $bigIntBytes = $value->toBytes(true); - - // Special case: MAX_UINT_64 will look like 00ffffffffffffffff and have an - // extra preceeding byte we need to get rid of - if (strlen($bigIntBytes) === 9 && substr($value->toHex(true), 0, 2) === '00') { - $bigIntBytes = substr($bigIntBytes, 1); - } - - $paddingChar = chr(0); - - $paddingBytes = 8 - strlen($bigIntBytes); - while ($paddingBytes > 0) { - $xdrBytes .= $paddingChar; - $paddingBytes--; - } - - $xdrBytes .= $bigIntBytes; - - return XdrEncoder::opaqueFixed($xdrBytes, 8); - } - - /** - * Use this to write raw bytes representing a 64-bit integer - * - * This value will be padded up to 8 bytes - * - * @param $value - * @return string - */ - public static function integer64RawBytes($value) - { - // Some libraries will give a 4-byte value here but it must be encoded - // as 8 - return self::applyPadding($value, 8, false); - } - - public static function unsignedInteger64($value) - { - if ($value > PHP_INT_MAX) throw new \InvalidArgumentException('value is greater than PHP_INT_MAX'); - - // unsigned 64-bit big-endian - return pack('J', $value); - } - - public static function signedHyper($value) - { - return self::signedInteger64($value); - } - - public static function unsignedHyper($value) - { - return self::unsignedInteger64($value); - } - - public static function unsignedInteger256($value) - { - return self::opaqueFixed($value, (256/8)); - } - - public static function boolean($value) - { - // Equivalent to 1 or 0 uint32 - return ($value) ? self::unsignedInteger(1) : self::unsignedInteger(0); - } - - /** - * @param $value - * @param null $maximumLength - * @return string - */ - public static function string($value, $maximumLength = null) - { - if ($maximumLength === null) $maximumLength = pow(2, 32) - 1; - - if (strlen($value) > $maximumLength) throw new \InvalidArgumentException('string exceeds maximum length'); - - $bytes = self::unsignedInteger(strlen($value)); - $bytes .= $value; - - // Pad with null bytes to get a multiple of 4 bytes - $remainder = (strlen($value) % 4); - if ($remainder) { - while ($remainder < 4) { - $bytes .= "\0"; - $remainder++; - } - } - - return $bytes; - } - - /** - * Encodes an optional data value as XDR. - * - * Any non-null $value will be encoded and returned - * - * @param XdrEncodableInterface $value - * @return string - */ - public static function optional(XdrEncodableInterface $value = null) - { - $bytes = ''; - - if ($value !== null) { - $bytes .= self::boolean(true); - $bytes .= $value->toXdr(); - } - else { - $bytes .= self::boolean(false); - } - - return $bytes; - } - - /** - * @param $value - * @return string - */ - public static function optionalUnsignedInteger($value) - { - $bytes = ''; - - if ($value !== null) { - $bytes .= self::boolean(true); - $bytes .= static::unsignedInteger($value); - } - else { - $bytes .= self::boolean(false); - } - - return $bytes; - } - - /** - * @param $value - * @return string - */ - public static function optionalString($value, $maximumLength) - { - $bytes = ''; - - if ($value !== null) { - $bytes .= self::boolean(true); - $bytes .= static::string($value, $maximumLength); - } - else { - $bytes .= self::boolean(false); - } - - return $bytes; - } - - /** - * Ensures $value's length is a multiple of $targetLength bytes - * - * The default value for XDR is 4 - * - * @param $value - * @param $targetLength - desired length after padding is applied - * @param $rightPadding - pad on the right of the value, false to pad to the left - * @return string - */ - private static function applyPadding($value, $targetLength = 4, $rightPadding = true) - { - // No padding necessary if it's a multiple of 4 bytes - if (strlen($value) % $targetLength === 0) return $value; - - $numPaddingChars = $targetLength - (strlen($value) % $targetLength); - - if ($rightPadding) { - return $value . str_repeat(chr(0), $numPaddingChars); - } - else { - return str_repeat(chr(0), $numPaddingChars) . $value; - } - } - - /** - * @return bool - */ - private static function nativeIsBigEndian() - { - if (null === self::$nativeIsBigEndian) { - self::$nativeIsBigEndian = pack('L', 1) === pack('N', 1); - } - - return self::$nativeIsBigEndian; - } + $expectedLength) throw new \InvalidArgumentException(sprintf('Unexpected length for value. Has length %s, expected %s', strlen($value), $expectedLength)); + if ($expectedLength && !$padUnexpectedLength && strlen($value) != $expectedLength) throw new \InvalidArgumentException(sprintf('Unexpected length for value. Has length %s, expected %s', strlen($value), $expectedLength)); + + if ($expectedLength && strlen($value) != $expectedLength) { + $value = self::applyPadding($value, $expectedLength); + } + + return self::applyPadding($value); + } + + /** + * Variable-length opaque data + * + * Maximum length is 2^32 - 1 + * + * @param $value + * @return string + */ + public static function opaqueVariable($value) + { + $maxLength = pow(2, 32) - 1; + if (strlen($value) > $maxLength) throw new \InvalidArgumentException(sprintf('Value of length %s is greater than the maximum allowed length of %s', strlen($value), $maxLength)); + + $bytes = ''; + + $bytes .= self::unsignedInteger(strlen($value)); + $bytes .= self::applyPadding($value); + + return $bytes; + } + + public static function signedInteger($value) + { + // pack() does not support a signed 32-byte int, so work around this with + // custom encoding + return (self::nativeIsBigEndian()) ? pack('l', $value) : strrev(pack('l', $value)); + } + + public static function unsignedInteger($value) + { + // unsigned 32-bit big-endian + return pack('N', $value); + } + + public static function signedInteger64($value) + { + // pack() does not support a signed 64-byte int, so work around this with + // custom encoding + return (self::nativeIsBigEndian()) ? pack('q', $value) : strrev(pack('q', $value)); + } + + /** + * Converts $value to a signed 8-byte big endian int64 + * + * @param BigInteger $value + * @return string + */ + public static function signedBigInteger64(BigInteger $value) + { + $xdrBytes = ''; + $bigIntBytes = $value->toBytes(true); + $bigIntBits = $value->toBits(true); + + // Special case: MAX_UINT_64 will look like 00ffffffffffffffff and have an + // extra preceeding byte we need to get rid of + if (strlen($bigIntBytes) === 9 && substr($value->toHex(true), 0, 2) === '00') { + $bigIntBytes = substr($bigIntBytes, 1); + } + + $paddingChar = chr(0); + // If the number is negative, pad with 0xFF + if (substr($bigIntBits, 0, 1) == 1) { + $paddingChar = chr(255); + } + + $paddingBytes = 8 - strlen($bigIntBytes); + while ($paddingBytes > 0) { + $xdrBytes .= $paddingChar; + $paddingBytes--; + } + + $xdrBytes .= $bigIntBytes; + + return XdrEncoder::opaqueFixed($xdrBytes, 8); + } + + /** + * Converts $value to an unsigned 8-byte big endian uint64 + * + * @param BigInteger $value + * @return string + */ + public static function unsignedBigInteger64(BigInteger $value) + { + $xdrBytes = ''; + $bigIntBytes = $value->toBytes(true); + + // Special case: MAX_UINT_64 will look like 00ffffffffffffffff and have an + // extra preceeding byte we need to get rid of + if (strlen($bigIntBytes) === 9 && substr($value->toHex(true), 0, 2) === '00') { + $bigIntBytes = substr($bigIntBytes, 1); + } + + $paddingChar = chr(0); + + $paddingBytes = 8 - strlen($bigIntBytes); + while ($paddingBytes > 0) { + $xdrBytes .= $paddingChar; + $paddingBytes--; + } + + $xdrBytes .= $bigIntBytes; + + return XdrEncoder::opaqueFixed($xdrBytes, 8); + } + + /** + * Use this to write raw bytes representing a 64-bit integer + * + * This value will be padded up to 8 bytes + * + * @param $value + * @return string + */ + public static function integer64RawBytes($value) + { + // Some libraries will give a 4-byte value here but it must be encoded + // as 8 + return self::applyPadding($value, 8, false); + } + + public static function unsignedInteger64($value) + { + if ($value > PHP_INT_MAX) throw new \InvalidArgumentException('value is greater than PHP_INT_MAX'); + + // unsigned 64-bit big-endian + return pack('J', $value); + } + + public static function signedHyper($value) + { + return self::signedInteger64($value); + } + + public static function unsignedHyper($value) + { + return self::unsignedInteger64($value); + } + + public static function unsignedInteger256($value) + { + return self::opaqueFixed($value, (256/8)); + } + + public static function boolean($value) + { + // Equivalent to 1 or 0 uint32 + return ($value) ? self::unsignedInteger(1) : self::unsignedInteger(0); + } + + /** + * @param $value + * @param null $maximumLength + * @return string + */ + public static function string($value, $maximumLength = null) + { + if ($maximumLength === null) $maximumLength = pow(2, 32) - 1; + + if (strlen($value) > $maximumLength) throw new \InvalidArgumentException('string exceeds maximum length'); + + $bytes = self::unsignedInteger(strlen($value)); + $bytes .= $value; + + // Pad with null bytes to get a multiple of 4 bytes + $remainder = (strlen($value) % 4); + if ($remainder) { + while ($remainder < 4) { + $bytes .= "\0"; + $remainder++; + } + } + + return $bytes; + } + + /** + * Encodes an optional data value as XDR. + * + * Any non-null $value will be encoded and returned + * + * @param XdrEncodableInterface $value + * @return string + */ + public static function optional(XdrEncodableInterface $value = null) + { + $bytes = ''; + + if ($value !== null) { + $bytes .= self::boolean(true); + $bytes .= $value->toXdr(); + } + else { + $bytes .= self::boolean(false); + } + + return $bytes; + } + + /** + * @param $value + * @return string + */ + public static function optionalUnsignedInteger($value) + { + $bytes = ''; + + if ($value !== null) { + $bytes .= self::boolean(true); + $bytes .= static::unsignedInteger($value); + } + else { + $bytes .= self::boolean(false); + } + + return $bytes; + } + + /** + * @param $value + * @return string + */ + public static function optionalString($value, $maximumLength) + { + $bytes = ''; + + if ($value !== null) { + $bytes .= self::boolean(true); + $bytes .= static::string($value, $maximumLength); + } + else { + $bytes .= self::boolean(false); + } + + return $bytes; + } + + /** + * Ensures $value's length is a multiple of $targetLength bytes + * + * The default value for XDR is 4 + * + * @param $value + * @param $targetLength - desired length after padding is applied + * @param $rightPadding - pad on the right of the value, false to pad to the left + * @return string + */ + private static function applyPadding($value, $targetLength = 4, $rightPadding = true) + { + // No padding necessary if it's a multiple of 4 bytes + if (strlen($value) % $targetLength === 0) return $value; + + $numPaddingChars = $targetLength - (strlen($value) % $targetLength); + + if ($rightPadding) { + return $value . str_repeat(chr(0), $numPaddingChars); + } + else { + return str_repeat(chr(0), $numPaddingChars) . $value; + } + } + + /** + * @return bool + */ + private static function nativeIsBigEndian() + { + if (null === self::$nativeIsBigEndian) { + self::$nativeIsBigEndian = pack('L', 1) === pack('N', 1); + } + + return self::$nativeIsBigEndian; + } } \ No newline at end of file diff --git a/src/XdrModel/AccountId.php b/src/XdrModel/AccountId.php index 4633e54..fcce495 100755 --- a/src/XdrModel/AccountId.php +++ b/src/XdrModel/AccountId.php @@ -1,110 +1,110 @@ -getPublicKey(); - } - - $this->accountIdString = $accountIdString; - $this->accountIdBytes = AddressableKey::getRawBytesFromBase32AccountId($accountIdString); - - $this->keyType = 0; - } - - /** - * @return string|Keypair - */ - public function getAccountIdString() - { - return $this->accountIdString; - } - - public function toXdr() - { - $bytes = ""; - - $bytes .= XdrEncoder::unsignedInteger(self::KEY_TYPE_ED25519); - $bytes .= XdrEncoder::opaqueFixed($this->accountIdBytes); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return AccountId - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $keyType = $xdr->readUnsignedInteger(); - $accountIdBytes = $xdr->readOpaqueFixed(32); - $accountIdString = AddressableKey::addressFromRawBytes($accountIdBytes); - - $model = new AccountId($accountIdString); - - $model->keyType = $keyType; - - return $model; - } - - /** - * @return int - */ - public function getKeyType() - { - return $this->keyType; - } +getPublicKey(); + } + + $this->accountIdString = $accountIdString; + $this->accountIdBytes = AddressableKey::getRawBytesFromBase32AccountId($accountIdString); + + $this->keyType = 0; + } + + /** + * @return string|Keypair + */ + public function getAccountIdString() + { + return $this->accountIdString; + } + + public function toXdr() + { + $bytes = ""; + + $bytes .= XdrEncoder::unsignedInteger(self::KEY_TYPE_ED25519); + $bytes .= XdrEncoder::opaqueFixed($this->accountIdBytes); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return AccountId + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $keyType = $xdr->readUnsignedInteger(); + $accountIdBytes = $xdr->readOpaqueFixed(32); + $accountIdString = AddressableKey::addressFromRawBytes($accountIdBytes); + + $model = new AccountId($accountIdString); + + $model->keyType = $keyType; + + return $model; + } + + /** + * @return int + */ + public function getKeyType() + { + return $this->keyType; + } } \ No newline at end of file diff --git a/src/XdrModel/AccountMergeResult.php b/src/XdrModel/AccountMergeResult.php index 653c8a7..c64b802 100644 --- a/src/XdrModel/AccountMergeResult.php +++ b/src/XdrModel/AccountMergeResult.php @@ -1,75 +1,75 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::MALFORMED, - '-2' => static::NO_ACCOUNT, - '-3' => static::IMMUTABLE_SET, - '-4' => static::HAS_SUB_ENTRIES, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - return $model; - } - - $model->transferredBalance = new StellarAmount(new BigInteger($xdr->readInteger64())); - - return $model; - } - - /** - * @return StellarAmount - */ - public function getTransferredBalance() - { - return $this->transferredBalance; - } - - /** - * @param StellarAmount $transferredBalance - */ - public function setTransferredBalance($transferredBalance) - { - $this->transferredBalance = $transferredBalance; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::MALFORMED, + '-2' => static::NO_ACCOUNT, + '-3' => static::IMMUTABLE_SET, + '-4' => static::HAS_SUB_ENTRIES, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + return $model; + } + + $model->transferredBalance = new StellarAmount(new BigInteger($xdr->readInteger64())); + + return $model; + } + + /** + * @return StellarAmount + */ + public function getTransferredBalance() + { + return $this->transferredBalance; + } + + /** + * @param StellarAmount $transferredBalance + */ + public function setTransferredBalance($transferredBalance) + { + $this->transferredBalance = $transferredBalance; + } } \ No newline at end of file diff --git a/src/XdrModel/AllowTrustResult.php b/src/XdrModel/AllowTrustResult.php index e72dbdc..aa6669d 100644 --- a/src/XdrModel/AllowTrustResult.php +++ b/src/XdrModel/AllowTrustResult.php @@ -1,49 +1,49 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::MALFORMED, - '-2' => static::NO_TRUST_LINE, - '-3' => static::TRUST_NOT_REQUIRED, - '-4' => static::CANT_REVOKE, - '-5' => static::SELF_NOT_ALLOWED, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - } - - return $model; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::MALFORMED, + '-2' => static::NO_TRUST_LINE, + '-3' => static::TRUST_NOT_REQUIRED, + '-4' => static::CANT_REVOKE, + '-5' => static::SELF_NOT_ALLOWED, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + } + + return $model; + } } \ No newline at end of file diff --git a/src/XdrModel/Asset.php b/src/XdrModel/Asset.php index 9d946f1..48e3256 100755 --- a/src/XdrModel/Asset.php +++ b/src/XdrModel/Asset.php @@ -1,181 +1,181 @@ - - * issuer: AccountId - * alphanum12: AssetAlphaNum12 - * assetCode: opaque<12> - * issuer: AccountId - */ -class Asset implements XdrEncodableInterface -{ - const TYPE_NATIVE = 0; - const TYPE_ALPHANUM_4 = 1; - const TYPE_ALPHANUM_12 = 2; - - /** - * See the TYPE_ constants - * - * @var int - */ - private $type; - - /** - * Either 4 or 12 bytes describing the asset code (depending on the value of $type) - * - * @var string - */ - private $assetCode; - - /** - * @var AccountId - */ - private $issuer; - - /** - * @return Asset - */ - public static function newNativeAsset() - { - return new Asset(Asset::TYPE_NATIVE); - } - - /** - * @param $code - * @param $issuerId - * @return Asset - */ - public static function newCustomAsset($code, $issuerId) - { - // Default to 4-character alphanum - $type = Asset::TYPE_ALPHANUM_4; - $codeLen = strlen($code); - - // todo: additional validation - if (!$codeLen || $codeLen > 12) throw new \InvalidArgumentException('Invalid code length (must be >=1 and <= 12'); - - if ($codeLen > 4) $type = Asset::TYPE_ALPHANUM_12; - - $asset = new Asset($type); - $asset->assetCode = $code; - $asset->issuer = new AccountId($issuerId); - - return $asset; - } - - public function __construct($type) - { - $this->type = $type; - } - - public function toXdr() - { - $bytes = ''; - - $bytes .= XdrEncoder::unsignedInteger($this->type); - - if ($this->type == self::TYPE_NATIVE) { - // no additional content for native types - } - elseif ($this->type == self::TYPE_ALPHANUM_4) { - $bytes .= XdrEncoder::opaqueFixed($this->assetCode, 4, true); - $bytes .= $this->issuer->toXdr(); - } - elseif ($this->type == self::TYPE_ALPHANUM_12) { - $bytes .= XdrEncoder::opaqueFixed($this->assetCode, 12, true); - $bytes .= $this->issuer->toXdr(); - } - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return Asset - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $type = $xdr->readUnsignedInteger(); - - $model = new Asset($type); - - if ($type == static::TYPE_ALPHANUM_4) { - $model->assetCode = $xdr->readOpaqueFixedString(4); - $model->issuer = AccountId::fromXdr($xdr); - } - if ($type == static::TYPE_ALPHANUM_12) { - $model->assetCode = $xdr->readOpaqueFixedString(12); - $model->issuer = AccountId::fromXdr($xdr); - } - - return $model; - } - - /** - * @return bool - */ - public function isNative() - { - return $this->type === static::TYPE_NATIVE; - } - - /** - * @return int - */ - public function getType() - { - return $this->type; - } - - /** - * @param int $type - */ - public function setType($type) - { - $this->type = $type; - } - - /** - * @return string - */ - public function getAssetCode() - { - return $this->assetCode; - } - - /** - * @param string $assetCode - */ - public function setAssetCode($assetCode) - { - $this->assetCode = $assetCode; - } - - /** - * @return AccountId - */ - public function getIssuer() - { - return $this->issuer; - } - - /** - * @param AccountId $issuer - */ - public function setIssuer($issuer) - { - $this->issuer = $issuer; - } + + * issuer: AccountId + * alphanum12: AssetAlphaNum12 + * assetCode: opaque<12> + * issuer: AccountId + */ +class Asset implements XdrEncodableInterface +{ + const TYPE_NATIVE = 0; + const TYPE_ALPHANUM_4 = 1; + const TYPE_ALPHANUM_12 = 2; + + /** + * See the TYPE_ constants + * + * @var int + */ + private $type; + + /** + * Either 4 or 12 bytes describing the asset code (depending on the value of $type) + * + * @var string + */ + private $assetCode; + + /** + * @var AccountId + */ + private $issuer; + + /** + * @return Asset + */ + public static function newNativeAsset() + { + return new Asset(Asset::TYPE_NATIVE); + } + + /** + * @param $code + * @param $issuerId + * @return Asset + */ + public static function newCustomAsset($code, $issuerId) + { + // Default to 4-character alphanum + $type = Asset::TYPE_ALPHANUM_4; + $codeLen = strlen($code); + + // todo: additional validation + if (!$codeLen || $codeLen > 12) throw new \InvalidArgumentException('Invalid code length (must be >=1 and <= 12'); + + if ($codeLen > 4) $type = Asset::TYPE_ALPHANUM_12; + + $asset = new Asset($type); + $asset->assetCode = $code; + $asset->issuer = new AccountId($issuerId); + + return $asset; + } + + public function __construct($type) + { + $this->type = $type; + } + + public function toXdr() + { + $bytes = ''; + + $bytes .= XdrEncoder::unsignedInteger($this->type); + + if ($this->type == self::TYPE_NATIVE) { + // no additional content for native types + } + elseif ($this->type == self::TYPE_ALPHANUM_4) { + $bytes .= XdrEncoder::opaqueFixed($this->assetCode, 4, true); + $bytes .= $this->issuer->toXdr(); + } + elseif ($this->type == self::TYPE_ALPHANUM_12) { + $bytes .= XdrEncoder::opaqueFixed($this->assetCode, 12, true); + $bytes .= $this->issuer->toXdr(); + } + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return Asset + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $type = $xdr->readUnsignedInteger(); + + $model = new Asset($type); + + if ($type == static::TYPE_ALPHANUM_4) { + $model->assetCode = $xdr->readOpaqueFixedString(4); + $model->issuer = AccountId::fromXdr($xdr); + } + if ($type == static::TYPE_ALPHANUM_12) { + $model->assetCode = $xdr->readOpaqueFixedString(12); + $model->issuer = AccountId::fromXdr($xdr); + } + + return $model; + } + + /** + * @return bool + */ + public function isNative() + { + return $this->type === static::TYPE_NATIVE; + } + + /** + * @return int + */ + public function getType() + { + return $this->type; + } + + /** + * @param int $type + */ + public function setType($type) + { + $this->type = $type; + } + + /** + * @return string + */ + public function getAssetCode() + { + return $this->assetCode; + } + + /** + * @param string $assetCode + */ + public function setAssetCode($assetCode) + { + $this->assetCode = $assetCode; + } + + /** + * @return AccountId + */ + public function getIssuer() + { + return $this->issuer; + } + + /** + * @param AccountId $issuer + */ + public function setIssuer($issuer) + { + $this->issuer = $issuer; + } } \ No newline at end of file diff --git a/src/XdrModel/BumpSequenceResult.php b/src/XdrModel/BumpSequenceResult.php index ab562f1..fa38057 100644 --- a/src/XdrModel/BumpSequenceResult.php +++ b/src/XdrModel/BumpSequenceResult.php @@ -1,41 +1,41 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::BAD_SEQ, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - } - - return $model; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::BAD_SEQ, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + } + + return $model; + } } \ No newline at end of file diff --git a/src/XdrModel/ChangeTrustResult.php b/src/XdrModel/ChangeTrustResult.php index 617ab02..87982cd 100644 --- a/src/XdrModel/ChangeTrustResult.php +++ b/src/XdrModel/ChangeTrustResult.php @@ -1,49 +1,49 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::MALFORMED, - '-2' => static::NO_ISSUER, - '-3' => static::INVALID_LIMIT, - '-4' => static::LOW_RESERVE, - '-5' => static::SELF_NOT_ALLOWED, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - } - - return $model; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::MALFORMED, + '-2' => static::NO_ISSUER, + '-3' => static::INVALID_LIMIT, + '-4' => static::LOW_RESERVE, + '-5' => static::SELF_NOT_ALLOWED, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + } + + return $model; + } } \ No newline at end of file diff --git a/src/XdrModel/ClaimOfferAtom.php b/src/XdrModel/ClaimOfferAtom.php index 8395516..f99b726 100644 --- a/src/XdrModel/ClaimOfferAtom.php +++ b/src/XdrModel/ClaimOfferAtom.php @@ -1,114 +1,114 @@ -seller = AccountId::fromXdr($xdr); - $model->offerId = $xdr->readUnsignedInteger64(); - - $model->assetSold = Asset::fromXdr($xdr); - $model->amountSold = new StellarAmount(new BigInteger($xdr->readInteger64())); - - $model->assetBought = Asset::fromXdr($xdr); - $model->amountBought = new StellarAmount(new BigInteger($xdr->readInteger64())); - - return $model; - } - - /** - * @return AccountId - */ - public function getSeller() - { - return $this->seller; - } - - /** - * @return int - */ - public function getOfferId() - { - return $this->offerId; - } - - /** - * @return Asset - */ - public function getAssetSold() - { - return $this->assetSold; - } - - /** - * @return StellarAmount - */ - public function getAmountSold() - { - return $this->amountSold; - } - - /** - * @return Asset - */ - public function getAssetBought() - { - return $this->assetBought; - } - - /** - * @return StellarAmount - */ - public function getAmountBought() - { - return $this->amountBought; - } +seller = AccountId::fromXdr($xdr); + $model->offerId = $xdr->readUnsignedInteger64(); + + $model->assetSold = Asset::fromXdr($xdr); + $model->amountSold = new StellarAmount(new BigInteger($xdr->readInteger64())); + + $model->assetBought = Asset::fromXdr($xdr); + $model->amountBought = new StellarAmount(new BigInteger($xdr->readInteger64())); + + return $model; + } + + /** + * @return AccountId + */ + public function getSeller() + { + return $this->seller; + } + + /** + * @return int + */ + public function getOfferId() + { + return $this->offerId; + } + + /** + * @return Asset + */ + public function getAssetSold() + { + return $this->assetSold; + } + + /** + * @return StellarAmount + */ + public function getAmountSold() + { + return $this->amountSold; + } + + /** + * @return Asset + */ + public function getAssetBought() + { + return $this->assetBought; + } + + /** + * @return StellarAmount + */ + public function getAmountBought() + { + return $this->amountBought; + } } \ No newline at end of file diff --git a/src/XdrModel/CreateAccountResult.php b/src/XdrModel/CreateAccountResult.php index 6ed783c..c084fd3 100644 --- a/src/XdrModel/CreateAccountResult.php +++ b/src/XdrModel/CreateAccountResult.php @@ -1,47 +1,47 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::MALFORMED, - '-2' => static::UNDERFUNDED, - '-3' => static::LOW_RESERVE, - '-4' => static::ALREADY_EXIST, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - } - - return $model; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::MALFORMED, + '-2' => static::UNDERFUNDED, + '-3' => static::LOW_RESERVE, + '-4' => static::ALREADY_EXIST, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + } + + return $model; + } } \ No newline at end of file diff --git a/src/XdrModel/DecoratedSignature.php b/src/XdrModel/DecoratedSignature.php index e8e1ba4..958348f 100755 --- a/src/XdrModel/DecoratedSignature.php +++ b/src/XdrModel/DecoratedSignature.php @@ -1,79 +1,79 @@ - - */ - private $hint; - - /** - * @var string opaque<64> - */ - private $signature; - - public function __construct($hint, $signature) - { - $this->hint = $hint; - $this->signature = $signature; - } - - public function toXdr() - { - $bytes = ''; - - $bytes .= XdrEncoder::opaqueFixed($this->hint, 4); - $bytes .= XdrEncoder::opaqueVariable($this->signature); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return DecoratedSignature - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $hint = $xdr->readOpaqueFixed(4); - $signature = $xdr->readOpaqueVariable(); - - return new DecoratedSignature($hint, $signature); - } - - /** - * @return string - */ - public function toBase64() - { - return base64_encode($this->toXdr()); - } - - /** - * @return string - */ - public function getWithoutHintBase64() - { - return base64_encode($this->signature); - } - - /** - * Returns the raw 64 bytes representing the signature - * - * This does not include the hint - * - * @return string - */ - public function getRawSignature() - { - return $this->signature; - } + + */ + private $hint; + + /** + * @var string opaque<64> + */ + private $signature; + + public function __construct($hint, $signature) + { + $this->hint = $hint; + $this->signature = $signature; + } + + public function toXdr() + { + $bytes = ''; + + $bytes .= XdrEncoder::opaqueFixed($this->hint, 4); + $bytes .= XdrEncoder::opaqueVariable($this->signature); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return DecoratedSignature + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $hint = $xdr->readOpaqueFixed(4); + $signature = $xdr->readOpaqueVariable(); + + return new DecoratedSignature($hint, $signature); + } + + /** + * @return string + */ + public function toBase64() + { + return base64_encode($this->toXdr()); + } + + /** + * @return string + */ + public function getWithoutHintBase64() + { + return base64_encode($this->signature); + } + + /** + * Returns the raw 64 bytes representing the signature + * + * This does not include the hint + * + * @return string + */ + public function getRawSignature() + { + return $this->signature; + } } \ No newline at end of file diff --git a/src/XdrModel/InflationPayout.php b/src/XdrModel/InflationPayout.php index bc3ce2b..56bb167 100644 --- a/src/XdrModel/InflationPayout.php +++ b/src/XdrModel/InflationPayout.php @@ -1,63 +1,63 @@ -destination = AccountId::fromXdr($xdr); - $model->amount = new StellarAmount($xdr->readInteger64()); - - return $model; - } - - /** - * @return AccountId - */ - public function getDestination() - { - return $this->destination; - } - - /** - * @param AccountId $destination - */ - public function setDestination($destination) - { - $this->destination = $destination; - } - - /** - * @return StellarAmount - */ - public function getAmount() - { - return $this->amount; - } - - /** - * @param StellarAmount $amount - */ - public function setAmount($amount) - { - $this->amount = $amount; - } +destination = AccountId::fromXdr($xdr); + $model->amount = new StellarAmount($xdr->readInteger64()); + + return $model; + } + + /** + * @return AccountId + */ + public function getDestination() + { + return $this->destination; + } + + /** + * @param AccountId $destination + */ + public function setDestination($destination) + { + $this->destination = $destination; + } + + /** + * @return StellarAmount + */ + public function getAmount() + { + return $this->amount; + } + + /** + * @param StellarAmount $amount + */ + public function setAmount($amount) + { + $this->amount = $amount; + } } \ No newline at end of file diff --git a/src/XdrModel/InflationResult.php b/src/XdrModel/InflationResult.php index f2506bf..0622e09 100644 --- a/src/XdrModel/InflationResult.php +++ b/src/XdrModel/InflationResult.php @@ -1,52 +1,52 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::NOT_TIME, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - return $model; - } - - $numPayouts = $xdr->readUnsignedInteger(); - for ($i=0; $i < $numPayouts; $i++) { - $model->payouts[] = InflationPayout::fromXdr($xdr); - } - - return $model; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::NOT_TIME, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + return $model; + } + + $numPayouts = $xdr->readUnsignedInteger(); + for ($i=0; $i < $numPayouts; $i++) { + $model->payouts[] = InflationPayout::fromXdr($xdr); + } + + return $model; + } } \ No newline at end of file diff --git a/src/XdrModel/ManageDataResult.php b/src/XdrModel/ManageDataResult.php index 66ea532..90f64b1 100644 --- a/src/XdrModel/ManageDataResult.php +++ b/src/XdrModel/ManageDataResult.php @@ -1,47 +1,47 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::NOT_SUPPORTED_YET, - '-2' => static::NAME_NOT_FOUND, - '-3' => static::LOW_RESERVE, - '-4' => static::INVALID_NAME, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - } - - return $model; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::NOT_SUPPORTED_YET, + '-2' => static::NAME_NOT_FOUND, + '-3' => static::LOW_RESERVE, + '-4' => static::INVALID_NAME, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + } + + return $model; + } } \ No newline at end of file diff --git a/src/XdrModel/ManageOfferResult.php b/src/XdrModel/ManageOfferResult.php index f12c0ce..02d5b42 100644 --- a/src/XdrModel/ManageOfferResult.php +++ b/src/XdrModel/ManageOfferResult.php @@ -1,125 +1,125 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::MALFORMED, - '-2' => static::SELL_NO_TRUST, - '-3' => static::BUY_NO_TRUST, - '-4' => static::SELL_NOT_AUTHORIZED, - '-5' => static::BUY_NOT_AUTHORIZED, - '-6' => static::LINE_FULL, - '-7' => static::UNDERFUNDED, - '-8' => static::CROSS_SELF, - '-9' => static::SELL_NO_ISSUER, - '-10' => static::BUY_NO_ISSUER, - '-11' => static::NOT_FOUND, - '-12' => static::LOW_RESERVE, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - // Return immediately if there was an error since there won't be any additional data - return $model; - } - - // Populate claimed offers - $numOffersClaimed = $xdr->readInteger(); - for ($i=0; $i < $numOffersClaimed; $i++) { - $model->claimedOffers[] = ClaimOfferAtom::fromXdr($xdr); - } - - $effect = $xdr->readInteger(); - if ($effect === static::EFFECT_CREATED || $effect === static::EFFECT_UPDATED) { - $model->offer = OfferEntry::fromXdr($xdr); - } - - return $model; - } - - /** - * @return ClaimOfferAtom[] - */ - public function getClaimedOffers() - { - return $this->claimedOffers; - } - - /** - * @param ClaimOfferAtom[] $claimedOffers - */ - public function setClaimedOffers($claimedOffers) - { - $this->claimedOffers = $claimedOffers; - } - - /** - * @return OfferEntry - */ - public function getOffer() - { - return $this->offer; - } - - /** - * @param OfferEntry $offer - */ - public function setOffer($offer) - { - $this->offer = $offer; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::MALFORMED, + '-2' => static::SELL_NO_TRUST, + '-3' => static::BUY_NO_TRUST, + '-4' => static::SELL_NOT_AUTHORIZED, + '-5' => static::BUY_NOT_AUTHORIZED, + '-6' => static::LINE_FULL, + '-7' => static::UNDERFUNDED, + '-8' => static::CROSS_SELF, + '-9' => static::SELL_NO_ISSUER, + '-10' => static::BUY_NO_ISSUER, + '-11' => static::NOT_FOUND, + '-12' => static::LOW_RESERVE, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + // Return immediately if there was an error since there won't be any additional data + return $model; + } + + // Populate claimed offers + $numOffersClaimed = $xdr->readInteger(); + for ($i=0; $i < $numOffersClaimed; $i++) { + $model->claimedOffers[] = ClaimOfferAtom::fromXdr($xdr); + } + + $effect = $xdr->readInteger(); + if ($effect === static::EFFECT_CREATED || $effect === static::EFFECT_UPDATED) { + $model->offer = OfferEntry::fromXdr($xdr); + } + + return $model; + } + + /** + * @return ClaimOfferAtom[] + */ + public function getClaimedOffers() + { + return $this->claimedOffers; + } + + /** + * @param ClaimOfferAtom[] $claimedOffers + */ + public function setClaimedOffers($claimedOffers) + { + $this->claimedOffers = $claimedOffers; + } + + /** + * @return OfferEntry + */ + public function getOffer() + { + return $this->offer; + } + + /** + * @param OfferEntry $offer + */ + public function setOffer($offer) + { + $this->offer = $offer; + } } \ No newline at end of file diff --git a/src/XdrModel/Memo.php b/src/XdrModel/Memo.php index 3614470..109e236 100755 --- a/src/XdrModel/Memo.php +++ b/src/XdrModel/Memo.php @@ -1,140 +1,146 @@ -type - * - * @var string - */ - private $value; - - public function __construct($type, $value = null) - { - $this->type = $type; - $this->value = $value; - - $this->validate(); - } - +type + * + * @var string + */ + private $value; + + public function __construct($type, $value = null) + { + $this->type = $type; + $this->value = $value; + + $this->validate(); + } + public function validate() { if ($this->type == static::MEMO_TYPE_NONE) return; if ($this->type == static::MEMO_TYPE_TEXT) { // Verify length does not exceed max - if (strlen($this->value) > static::VALUE_TEXT_MAX_SIZE) { + $value = ($this->value === null) ? '' : (string)$this->value; + if (strlen($value) > static::VALUE_TEXT_MAX_SIZE) { throw new \ErrorException(sprintf('memo text is greater than the maximum of %s bytes', static::VALUE_TEXT_MAX_SIZE)); } + // Normalize stored value to a string to avoid null-related deprecations + $this->value = $value; } if ($this->type == static::MEMO_TYPE_ID) { if ($this->value < 0) throw new \ErrorException('value cannot be negative'); if ($this->value > PHP_INT_MAX) throw new \ErrorException(sprintf('value cannot be larger than %s', PHP_INT_MAX)); } if ($this->type == static::MEMO_TYPE_HASH || $this->type == static::MEMO_TYPE_RETURN) { - if (strlen($this->value) != 32) throw new \InvalidArgumentException(sprintf('hash values must be 32 bytes, got %s bytes', strlen($this->value))); - } - } - - public function toXdr() - { - $this->validate(); - $bytes = ''; - - // Type - $bytes .= XdrEncoder::unsignedInteger($this->type); - - // Value - if ($this->type == static::MEMO_TYPE_NONE) { - // no-op - } - if ($this->type == static::MEMO_TYPE_TEXT) { - $bytes .= XdrEncoder::string($this->value, static::VALUE_TEXT_MAX_SIZE); - } - if ($this->type == static::MEMO_TYPE_ID) { - $bytes .= XdrEncoder::unsignedInteger64($this->value); - } - if ($this->type == static::MEMO_TYPE_HASH) { - $bytes .= XdrEncoder::opaqueFixed($this->value, 32); - } - if ($this->type == static::MEMO_TYPE_RETURN) { - $bytes .= XdrEncoder::opaqueFixed($this->value, 32); - } - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return Memo - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $type = $xdr->readUnsignedInteger(); - - $memo = new Memo($type); - - if ($memo->type == static::MEMO_TYPE_TEXT) { - $memo->value = $xdr->readString(static::VALUE_TEXT_MAX_SIZE); - } - if ($memo->type == static::MEMO_TYPE_ID) { - $memo->value = $xdr->readBigInteger()->toString(); - } - if ($memo->type == static::MEMO_TYPE_HASH - || $memo->type == static::MEMO_TYPE_RETURN) { - $memo->value = $xdr->readOpaqueFixed(32); + if (!is_string($this->value) || strlen($this->value) != 32) { + $len = is_string($this->value) ? strlen($this->value) : 'non-string'; + throw new \InvalidArgumentException(sprintf('hash values must be 32 bytes, got %s', $len)); + } } - - return $memo; - } - - /** - * @return int - */ - public function getType() - { - return $this->type; - } - - /** - * @return string - */ - public function getValue() - { - return $this->value; } -} \ No newline at end of file + + public function toXdr() + { + $this->validate(); + $bytes = ''; + + // Type + $bytes .= XdrEncoder::unsignedInteger($this->type); + + // Value + if ($this->type == static::MEMO_TYPE_NONE) { + // no-op + } + if ($this->type == static::MEMO_TYPE_TEXT) { + $bytes .= XdrEncoder::string($this->value, static::VALUE_TEXT_MAX_SIZE); + } + if ($this->type == static::MEMO_TYPE_ID) { + $bytes .= XdrEncoder::unsignedInteger64($this->value); + } + if ($this->type == static::MEMO_TYPE_HASH) { + $bytes .= XdrEncoder::opaqueFixed($this->value, 32); + } + if ($this->type == static::MEMO_TYPE_RETURN) { + $bytes .= XdrEncoder::opaqueFixed($this->value, 32); + } + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return Memo + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $type = $xdr->readUnsignedInteger(); + + $memo = new Memo($type); + + if ($memo->type == static::MEMO_TYPE_TEXT) { + $memo->value = $xdr->readString(static::VALUE_TEXT_MAX_SIZE); + } + if ($memo->type == static::MEMO_TYPE_ID) { + $memo->value = $xdr->readBigInteger()->toString(); + } + if ($memo->type == static::MEMO_TYPE_HASH + || $memo->type == static::MEMO_TYPE_RETURN) { + $memo->value = $xdr->readOpaqueFixed(32); + } + + return $memo; + } + + /** + * @return int + */ + public function getType() + { + return $this->type; + } + + /** + * @return string + */ + public function getValue() + { + return $this->value; + } +} diff --git a/src/XdrModel/OfferEntry.php b/src/XdrModel/OfferEntry.php index d6ba3ec..9200d35 100644 --- a/src/XdrModel/OfferEntry.php +++ b/src/XdrModel/OfferEntry.php @@ -1,192 +1,192 @@ -seller = AccountId::fromXdr($xdr); - $model->offerId = $xdr->readUnsignedInteger64(); - - $model->sellingAsset = Asset::fromXdr($xdr); - $model->buyingAsset = Asset::fromXdr($xdr); - $model->sellingAmount = new StellarAmount(new BigInteger($xdr->readInteger64())); - $model->price = Price::fromXdr($xdr); - - $flags = $xdr->readUnsignedInteger(); - - if ($flags & OfferEntry::FLAG_IS_PASSIVE) { - $model->isPassive = true; - } - - return $model; - } - - /** - * @return AccountId - */ - public function getSeller() - { - return $this->seller; - } - - /** - * @param AccountId $seller - */ - public function setSeller($seller) - { - $this->seller = $seller; - } - - /** - * @return BigInteger - */ - public function getOfferId() - { - return $this->offerId; - } - - /** - * @param BigInteger $offerId - */ - public function setOfferId($offerId) - { - $this->offerId = $offerId; - } - - /** - * @return Asset - */ - public function getSellingAsset() - { - return $this->sellingAsset; - } - - /** - * @param Asset $sellingAsset - */ - public function setSellingAsset($sellingAsset) - { - $this->sellingAsset = $sellingAsset; - } - - /** - * @return Asset - */ - public function getBuyingAsset() - { - return $this->buyingAsset; - } - - /** - * @param Asset $buyingAsset - */ - public function setBuyingAsset($buyingAsset) - { - $this->buyingAsset = $buyingAsset; - } - - /** - * @return StellarAmount - */ - public function getSellingAmount() - { - return $this->sellingAmount; - } - - /** - * @param StellarAmount $sellingAmount - */ - public function setSellingAmount($sellingAmount) - { - $this->sellingAmount = $sellingAmount; - } - - /** - * @return Price - */ - public function getPrice() - { - return $this->price; - } - - /** - * @param Price $price - */ - public function setPrice($price) - { - $this->price = $price; - } - - /** - * @return bool - */ - public function isPassive() - { - return $this->isPassive; - } - - /** - * @param bool $isPassive - */ - public function setIsPassive($isPassive) - { - $this->isPassive = $isPassive; - } +seller = AccountId::fromXdr($xdr); + $model->offerId = $xdr->readUnsignedInteger64(); + + $model->sellingAsset = Asset::fromXdr($xdr); + $model->buyingAsset = Asset::fromXdr($xdr); + $model->sellingAmount = new StellarAmount(new BigInteger($xdr->readInteger64())); + $model->price = Price::fromXdr($xdr); + + $flags = $xdr->readUnsignedInteger(); + + if ($flags & OfferEntry::FLAG_IS_PASSIVE) { + $model->isPassive = true; + } + + return $model; + } + + /** + * @return AccountId + */ + public function getSeller() + { + return $this->seller; + } + + /** + * @param AccountId $seller + */ + public function setSeller($seller) + { + $this->seller = $seller; + } + + /** + * @return BigInteger + */ + public function getOfferId() + { + return $this->offerId; + } + + /** + * @param BigInteger $offerId + */ + public function setOfferId($offerId) + { + $this->offerId = $offerId; + } + + /** + * @return Asset + */ + public function getSellingAsset() + { + return $this->sellingAsset; + } + + /** + * @param Asset $sellingAsset + */ + public function setSellingAsset($sellingAsset) + { + $this->sellingAsset = $sellingAsset; + } + + /** + * @return Asset + */ + public function getBuyingAsset() + { + return $this->buyingAsset; + } + + /** + * @param Asset $buyingAsset + */ + public function setBuyingAsset($buyingAsset) + { + $this->buyingAsset = $buyingAsset; + } + + /** + * @return StellarAmount + */ + public function getSellingAmount() + { + return $this->sellingAmount; + } + + /** + * @param StellarAmount $sellingAmount + */ + public function setSellingAmount($sellingAmount) + { + $this->sellingAmount = $sellingAmount; + } + + /** + * @return Price + */ + public function getPrice() + { + return $this->price; + } + + /** + * @param Price $price + */ + public function setPrice($price) + { + $this->price = $price; + } + + /** + * @return bool + */ + public function isPassive() + { + return $this->isPassive; + } + + /** + * @param bool $isPassive + */ + public function setIsPassive($isPassive) + { + $this->isPassive = $isPassive; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/AccountMergeOp.php b/src/XdrModel/Operation/AccountMergeOp.php index 15e51a1..eb300e7 100644 --- a/src/XdrModel/Operation/AccountMergeOp.php +++ b/src/XdrModel/Operation/AccountMergeOp.php @@ -1,73 +1,73 @@ -getPublicKey(); - } - - $this->destination = new AccountId($destinationAccountId); - } - - /** - * @return string - */ - public function toXdr() - { - $bytes = parent::toXdr(); - - // Destination account - $bytes .= $this->destination->toXdr(); - - return $bytes; - } - - /** - * NOTE: This only parses the XDR that's specific to this operation and cannot - * load a full Operation - * - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return AccountMergeOp - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $destination = AccountId::fromXdr($xdr); - - return new AccountMergeOp($destination->getAccountIdString()); - } - - /** - * @return AccountId - */ - public function getDestination() - { - return $this->destination; - } - - /** - * @param AccountId $destination - */ - public function setDestination($destination) - { - $this->destination = $destination; - } +getPublicKey(); + } + + $this->destination = new AccountId($destinationAccountId); + } + + /** + * @return string + */ + public function toXdr() + { + $bytes = parent::toXdr(); + + // Destination account + $bytes .= $this->destination->toXdr(); + + return $bytes; + } + + /** + * NOTE: This only parses the XDR that's specific to this operation and cannot + * load a full Operation + * + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return AccountMergeOp + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $destination = AccountId::fromXdr($xdr); + + return new AccountMergeOp($destination->getAccountIdString()); + } + + /** + * @return AccountId + */ + public function getDestination() + { + return $this->destination; + } + + /** + * @param AccountId $destination + */ + public function setDestination($destination) + { + $this->destination = $destination; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/AllowTrustOp.php b/src/XdrModel/Operation/AllowTrustOp.php index d60a98e..b663963 100644 --- a/src/XdrModel/Operation/AllowTrustOp.php +++ b/src/XdrModel/Operation/AllowTrustOp.php @@ -1,147 +1,147 @@ -isNative()) throw new \InvalidArgumentException('Trust cannot be added for native assets'); - - parent::__construct(Operation::TYPE_ALLOW_TRUST, $sourceAccountId); - - $this->asset = $asset; - $this->trustor = $trustor; - // $this->isAuthorized intentionally left null - } - - /** - * @return string - * @throws \ErrorException - */ - public function toXdr() - { - // isAuthorized must be set to a value - if ($this->isAuthorized === null) throw new \ErrorException('isAuthorized must be set to true or false'); - - $bytes = parent::toXdr(); - - // Trusted account - $bytes .= $this->trustor->toXdr(); - - // Asset is encoded as a union - $bytes .= XdrEncoder::unsignedInteger($this->asset->getType()); - if ($this->asset->getType() == Asset::TYPE_ALPHANUM_4) { - $bytes .= XdrEncoder::opaqueFixed($this->asset->getAssetCode(), 4, true); - } - elseif ($this->asset->getType() == Asset::TYPE_ALPHANUM_12) { - $bytes .= XdrEncoder::opaqueFixed($this->asset->getAssetCode(), 12, true); - } - - // Is authorized? - $bytes .= XdrEncoder::boolean($this->isAuthorized); - - return $bytes; - } - - /** - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return AllowTrustOp|Operation - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $trustedAccount = AccountId::fromXdr($xdr); - - // Needs to be manually decoded since issuer is not present in the XDR - $assetType = $xdr->readUnsignedInteger(); - $assetCode = null; - if ($assetType === Asset::TYPE_ALPHANUM_4) { - $assetCode = $xdr->readOpaqueFixedString(4); - } - if ($assetType === Asset::TYPE_ALPHANUM_12) { - $assetCode = $xdr->readOpaqueFixedString(12); - } - - $asset = new Asset($assetType); - $asset->setAssetCode($assetCode); - - $model = new AllowTrustOp($asset, $trustedAccount); - $model->setIsAuthorized($xdr->readBoolean()); - - return $model; - } - - /** - * @return Asset - */ - public function getAsset() - { - return $this->asset; - } - - /** - * @param Asset $asset - */ - public function setAsset($asset) - { - $this->asset = $asset; - } - - /** - * @return AccountId - */ - public function getTrustor() - { - return $this->trustor; - } - - /** - * @param AccountId $trustor - */ - public function setTrustor($trustor) - { - $this->trustor = $trustor; - } - - /** - * @return bool - */ - public function isAuthorized() - { - return $this->isAuthorized; - } - - /** - * @param bool $isAuthorized - */ - public function setIsAuthorized($isAuthorized) - { - $this->isAuthorized = $isAuthorized; - } +isNative()) throw new \InvalidArgumentException('Trust cannot be added for native assets'); + + parent::__construct(Operation::TYPE_ALLOW_TRUST, $sourceAccountId); + + $this->asset = $asset; + $this->trustor = $trustor; + // $this->isAuthorized intentionally left null + } + + /** + * @return string + * @throws \ErrorException + */ + public function toXdr() + { + // isAuthorized must be set to a value + if ($this->isAuthorized === null) throw new \ErrorException('isAuthorized must be set to true or false'); + + $bytes = parent::toXdr(); + + // Trusted account + $bytes .= $this->trustor->toXdr(); + + // Asset is encoded as a union + $bytes .= XdrEncoder::unsignedInteger($this->asset->getType()); + if ($this->asset->getType() == Asset::TYPE_ALPHANUM_4) { + $bytes .= XdrEncoder::opaqueFixed($this->asset->getAssetCode(), 4, true); + } + elseif ($this->asset->getType() == Asset::TYPE_ALPHANUM_12) { + $bytes .= XdrEncoder::opaqueFixed($this->asset->getAssetCode(), 12, true); + } + + // Is authorized? + $bytes .= XdrEncoder::boolean($this->isAuthorized); + + return $bytes; + } + + /** + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return AllowTrustOp|Operation + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $trustedAccount = AccountId::fromXdr($xdr); + + // Needs to be manually decoded since issuer is not present in the XDR + $assetType = $xdr->readUnsignedInteger(); + $assetCode = null; + if ($assetType === Asset::TYPE_ALPHANUM_4) { + $assetCode = $xdr->readOpaqueFixedString(4); + } + if ($assetType === Asset::TYPE_ALPHANUM_12) { + $assetCode = $xdr->readOpaqueFixedString(12); + } + + $asset = new Asset($assetType); + $asset->setAssetCode($assetCode); + + $model = new AllowTrustOp($asset, $trustedAccount); + $model->setIsAuthorized($xdr->readBoolean()); + + return $model; + } + + /** + * @return Asset + */ + public function getAsset() + { + return $this->asset; + } + + /** + * @param Asset $asset + */ + public function setAsset($asset) + { + $this->asset = $asset; + } + + /** + * @return AccountId + */ + public function getTrustor() + { + return $this->trustor; + } + + /** + * @param AccountId $trustor + */ + public function setTrustor($trustor) + { + $this->trustor = $trustor; + } + + /** + * @return bool + */ + public function isAuthorized() + { + return $this->isAuthorized; + } + + /** + * @param bool $isAuthorized + */ + public function setIsAuthorized($isAuthorized) + { + $this->isAuthorized = $isAuthorized; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/BumpSequenceOp.php b/src/XdrModel/Operation/BumpSequenceOp.php index d75d704..4d6a8ca 100644 --- a/src/XdrModel/Operation/BumpSequenceOp.php +++ b/src/XdrModel/Operation/BumpSequenceOp.php @@ -1,67 +1,67 @@ -bumpTo = $bumpTo; - } - - /** - * @return string - */ - public function toXdr() - { - $bytes = parent::toXdr(); - - $bytes .= XdrEncoder::unsignedBigInteger64($this->bumpTo); - - return $bytes; - } - - /** - * NOTE: This only parses the XDR that's specific to this operation and cannot - * load a full Operation - * - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return BumpSequenceOp - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - return new BumpSequenceOp($xdr->readBigInteger()); - } - - /** - * @return BigInteger - */ - public function getBumpTo() - { - return $this->bumpTo; - } - - /** - * @param BigInteger $bumpTo - */ - public function setBumpTo($bumpTo) - { - $this->bumpTo = $bumpTo; - } +bumpTo = $bumpTo; + } + + /** + * @return string + */ + public function toXdr() + { + $bytes = parent::toXdr(); + + $bytes .= XdrEncoder::unsignedBigInteger64($this->bumpTo); + + return $bytes; + } + + /** + * NOTE: This only parses the XDR that's specific to this operation and cannot + * load a full Operation + * + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return BumpSequenceOp + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + return new BumpSequenceOp($xdr->readBigInteger()); + } + + /** + * @return BigInteger + */ + public function getBumpTo() + { + return $this->bumpTo; + } + + /** + * @param BigInteger $bumpTo + */ + public function setBumpTo($bumpTo) + { + $this->bumpTo = $bumpTo; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/ChangeTrustOp.php b/src/XdrModel/Operation/ChangeTrustOp.php index 3307e83..df6bdb2 100644 --- a/src/XdrModel/Operation/ChangeTrustOp.php +++ b/src/XdrModel/Operation/ChangeTrustOp.php @@ -1,110 +1,110 @@ -asset = $asset; - $this->setLimit($limit); - } - - public function toXdr() - { - $bytes = parent::toXdr(); - - $bytes .= $this->asset->toXdr(); - $bytes .= XdrEncoder::signedBigInteger64($this->limit->getUnscaledBigInteger()); - - return $bytes; - } - - /** - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return ChangeTrustOp|Operation - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $asset = Asset::fromXdr($xdr); - $limit = StellarAmount::fromXdr($xdr); - - return new ChangeTrustOp($asset, $limit->getUnscaledBigInteger()); - } - - /** - * Sets the limit of the trust line to the maximum amount - */ - public function setMaxLimit() - { - $this->limit = StellarAmount::newMaximum(); - } - - /** - * @return StellarAmount - */ - public function getLimit() - { - return $this->limit; - } - - /** - * @param int|BigInteger $limit int representing lumens or BigInteger representing stroops - */ - public function setLimit($limit) - { - $this->limit = new StellarAmount($limit); - } - - /** - * @return Asset - */ - public function getAsset() - { - return $this->asset; - } - - /** - * @param Asset $asset - */ - public function setAsset($asset) - { - $this->asset = $asset; - } +asset = $asset; + $this->setLimit($limit); + } + + public function toXdr() + { + $bytes = parent::toXdr(); + + $bytes .= $this->asset->toXdr(); + $bytes .= XdrEncoder::signedBigInteger64($this->limit->getUnscaledBigInteger()); + + return $bytes; + } + + /** + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return ChangeTrustOp|Operation + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $asset = Asset::fromXdr($xdr); + $limit = StellarAmount::fromXdr($xdr); + + return new ChangeTrustOp($asset, $limit->getUnscaledBigInteger()); + } + + /** + * Sets the limit of the trust line to the maximum amount + */ + public function setMaxLimit() + { + $this->limit = StellarAmount::newMaximum(); + } + + /** + * @return StellarAmount + */ + public function getLimit() + { + return $this->limit; + } + + /** + * @param int|BigInteger $limit int representing lumens or BigInteger representing stroops + */ + public function setLimit($limit) + { + $this->limit = new StellarAmount($limit); + } + + /** + * @return Asset + */ + public function getAsset() + { + return $this->asset; + } + + /** + * @param Asset $asset + */ + public function setAsset($asset) + { + $this->asset = $asset; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/CreateAccountOp.php b/src/XdrModel/Operation/CreateAccountOp.php index de1415e..bd76993 100644 --- a/src/XdrModel/Operation/CreateAccountOp.php +++ b/src/XdrModel/Operation/CreateAccountOp.php @@ -1,108 +1,108 @@ -getPublicKey()); - } - if (is_string($sourceAccount)) { - $sourceAccount = new AccountId($sourceAccount); - } - - parent::__construct( Operation::TYPE_CREATE_ACCOUNT, $sourceAccount); - - $this->newAccount = $newAccount; - $this->startingBalance = new StellarAmount($startingBalance); - } - - /** - * @return string XDR bytes - */ - public function toXdr() - { - $bytes = parent::toXdr(); - - $bytes .= $this->newAccount->toXdr(); - $bytes .= XdrEncoder::signedBigInteger64($this->startingBalance->getUnscaledBigInteger()); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return CreateAccountOp|Operation - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $newAccountId = AccountId::fromXdr($xdr); - $startingBalance = new BigInteger($xdr->readInteger64()); - - return new CreateAccountOp($newAccountId, $startingBalance); - } - - /** - * @return AccountId - */ - public function getNewAccount() - { - return $this->newAccount; - } - - /** - * @param AccountId $newAccount - */ - public function setNewAccount($newAccount) - { - $this->newAccount = $newAccount; - } - - /** - * @return StellarAmount - */ - public function getStartingBalance() - { - return $this->startingBalance; - } - - /** - * @param StellarAmount $startingBalance - */ - public function setStartingBalance($startingBalance) - { - $this->startingBalance = $startingBalance; - } +getPublicKey()); + } + if (is_string($sourceAccount)) { + $sourceAccount = new AccountId($sourceAccount); + } + + parent::__construct( Operation::TYPE_CREATE_ACCOUNT, $sourceAccount); + + $this->newAccount = $newAccount; + $this->startingBalance = new StellarAmount($startingBalance); + } + + /** + * @return string XDR bytes + */ + public function toXdr() + { + $bytes = parent::toXdr(); + + $bytes .= $this->newAccount->toXdr(); + $bytes .= XdrEncoder::signedBigInteger64($this->startingBalance->getUnscaledBigInteger()); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return CreateAccountOp|Operation + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $newAccountId = AccountId::fromXdr($xdr); + $startingBalance = new BigInteger($xdr->readInteger64()); + + return new CreateAccountOp($newAccountId, $startingBalance); + } + + /** + * @return AccountId + */ + public function getNewAccount() + { + return $this->newAccount; + } + + /** + * @param AccountId $newAccount + */ + public function setNewAccount($newAccount) + { + $this->newAccount = $newAccount; + } + + /** + * @return StellarAmount + */ + public function getStartingBalance() + { + return $this->startingBalance; + } + + /** + * @param StellarAmount $startingBalance + */ + public function setStartingBalance($startingBalance) + { + $this->startingBalance = $startingBalance; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/CreatePassiveOfferOp.php b/src/XdrModel/Operation/CreatePassiveOfferOp.php index 544f9fc..1d9b63e 100644 --- a/src/XdrModel/Operation/CreatePassiveOfferOp.php +++ b/src/XdrModel/Operation/CreatePassiveOfferOp.php @@ -1,164 +1,164 @@ -sellingAsset = $sellingAsset; - $this->buyingAsset = $buyingAsset; - $this->amount = new StellarAmount($amount); - $this->price = $price; - } - - /** - * @return string XDR bytes - */ - public function toXdr() - { - $bytes = parent::toXdr(); - - $bytes .= $this->sellingAsset->toXdr(); - $bytes .= $this->buyingAsset->toXdr(); - $bytes .= XdrEncoder::signedBigInteger64($this->amount->getUnscaledBigInteger()); - $bytes .= $this->price->toXdr(); - - return $bytes; - } - - /** - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return ManageOfferOp|Operation - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $sellingAsset = Asset::fromXdr($xdr); - $buyingAsset = Asset::fromXdr($xdr); - $amount = StellarAmount::fromXdr($xdr); - $price = Price::fromXdr($xdr); - - return new CreatePassiveOfferOp($sellingAsset, - $buyingAsset, - $amount->getUnscaledBigInteger(), - $price - ); - } - - /** - * @return Asset - */ - public function getSellingAsset() - { - return $this->sellingAsset; - } - - /** - * @param Asset $sellingAsset - */ - public function setSellingAsset($sellingAsset) - { - $this->sellingAsset = $sellingAsset; - } - - /** - * @return Asset - */ - public function getBuyingAsset() - { - return $this->buyingAsset; - } - - /** - * @param Asset $buyingAsset - */ - public function setBuyingAsset($buyingAsset) - { - $this->buyingAsset = $buyingAsset; - } - - /** - * @return StellarAmount - */ - public function getAmount() - { - return $this->amount; - } - - /** - * @param int $amount - */ - public function setAmount($amount) - { - $this->amount = $amount; - } - - /** - * @return Price - */ - public function getPrice() - { - return $this->price; - } - - /** - * @param Price $price - */ - public function setPrice($price) - { - $this->price = $price; - } +sellingAsset = $sellingAsset; + $this->buyingAsset = $buyingAsset; + $this->amount = new StellarAmount($amount); + $this->price = $price; + } + + /** + * @return string XDR bytes + */ + public function toXdr() + { + $bytes = parent::toXdr(); + + $bytes .= $this->sellingAsset->toXdr(); + $bytes .= $this->buyingAsset->toXdr(); + $bytes .= XdrEncoder::signedBigInteger64($this->amount->getUnscaledBigInteger()); + $bytes .= $this->price->toXdr(); + + return $bytes; + } + + /** + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return ManageOfferOp|Operation + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $sellingAsset = Asset::fromXdr($xdr); + $buyingAsset = Asset::fromXdr($xdr); + $amount = StellarAmount::fromXdr($xdr); + $price = Price::fromXdr($xdr); + + return new CreatePassiveOfferOp($sellingAsset, + $buyingAsset, + $amount->getUnscaledBigInteger(), + $price + ); + } + + /** + * @return Asset + */ + public function getSellingAsset() + { + return $this->sellingAsset; + } + + /** + * @param Asset $sellingAsset + */ + public function setSellingAsset($sellingAsset) + { + $this->sellingAsset = $sellingAsset; + } + + /** + * @return Asset + */ + public function getBuyingAsset() + { + return $this->buyingAsset; + } + + /** + * @param Asset $buyingAsset + */ + public function setBuyingAsset($buyingAsset) + { + $this->buyingAsset = $buyingAsset; + } + + /** + * @return StellarAmount + */ + public function getAmount() + { + return $this->amount; + } + + /** + * @param int $amount + */ + public function setAmount($amount) + { + $this->amount = $amount; + } + + /** + * @return Price + */ + public function getPrice() + { + return $this->price; + } + + /** + * @param Price $price + */ + public function setPrice($price) + { + $this->price = $price; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/InflationOp.php b/src/XdrModel/Operation/InflationOp.php index 7aaa774..3398e25 100644 --- a/src/XdrModel/Operation/InflationOp.php +++ b/src/XdrModel/Operation/InflationOp.php @@ -1,16 +1,16 @@ -setKey($key); - $this->setValue($value); - } - - /** - * @return string - */ - public function toXdr() - { - $bytes = parent::toXdr(); - - // Key - $bytes .= XdrEncoder::string($this->key, 64); - - // Value (an optional field) - if ($this->value) { - $bytes .= XdrEncoder::boolean(true); - $bytes .= XdrEncoder::opaqueVariable($this->value); - } - else { - $bytes .= XdrEncoder::boolean(false); - } - - return $bytes; - } - - /** - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return ManageDataOp|Operation - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $key = $xdr->readString(64); - - $value = null; - if ($xdr->readBoolean()) { - $value = $xdr->readOpaqueVariable(64); - } - - return new ManageDataOp($key, $value); - } - - /** - * @return string - */ - public function getKey() - { - return $this->key; - } - - /** - * @param string $key - */ - public function setKey($key) - { - if (strlen($key) > 64) throw new \InvalidArgumentException('key cannot be longer than 64 characters'); - - $this->key = $key; - } - - /** - * @return string - */ - public function getValue() - { - return $this->value; - } - - /** - * @param string $value - */ - public function setValue($value = null) - { - if (strlen($value) > 64) throw new \InvalidArgumentException('value cannot be longer than 64 characters'); - - $this->value = $value; - } +setKey($key); + $this->setValue($value); + } + + /** + * @return string + */ + public function toXdr() + { + $bytes = parent::toXdr(); + + // Key + $bytes .= XdrEncoder::string($this->key, 64); + + // Value (an optional field) + if ($this->value) { + $bytes .= XdrEncoder::boolean(true); + $bytes .= XdrEncoder::opaqueVariable($this->value); + } + else { + $bytes .= XdrEncoder::boolean(false); + } + + return $bytes; + } + + /** + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return ManageDataOp|Operation + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $key = $xdr->readString(64); + + $value = null; + if ($xdr->readBoolean()) { + $value = $xdr->readOpaqueVariable(64); + } + + return new ManageDataOp($key, $value); + } + + /** + * @return string + */ + public function getKey() + { + return $this->key; + } + + /** + * @param string $key + */ + public function setKey($key) + { + if (strlen($key) > 64) throw new \InvalidArgumentException('key cannot be longer than 64 characters'); + + $this->key = $key; + } + + /** + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * @param string $value + */ + public function setValue($value = null) + { + if (strlen($value) > 64) throw new \InvalidArgumentException('value cannot be longer than 64 characters'); + + $this->value = $value; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/ManageOfferOp.php b/src/XdrModel/Operation/ManageOfferOp.php index 1f1df8b..7b46970 100644 --- a/src/XdrModel/Operation/ManageOfferOp.php +++ b/src/XdrModel/Operation/ManageOfferOp.php @@ -1,190 +1,190 @@ -sellingAsset = $sellingAsset; - $this->buyingAsset = $buyingAsset; - $this->amount = new StellarAmount($amount); - $this->price = $price; - $this->offerId = $offerId; - } - - /** - * @return string XDR bytes - */ - public function toXdr() - { - $bytes = parent::toXdr(); - - $bytes .= $this->sellingAsset->toXdr(); - $bytes .= $this->buyingAsset->toXdr(); - $bytes .= XdrEncoder::signedBigInteger64($this->amount->getUnscaledBigInteger()); - $bytes .= $this->price->toXdr(); - $bytes .= XdrEncoder::unsignedInteger64($this->offerId); - - return $bytes; - } - - /** - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return ManageOfferOp|Operation - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $sellingAsset = Asset::fromXdr($xdr); - $buyingAsset = Asset::fromXdr($xdr); - $amount = StellarAmount::fromXdr($xdr); - $price = Price::fromXdr($xdr); - $offerId = $xdr->readUnsignedInteger64(); - - return new ManageOfferOp($sellingAsset, - $buyingAsset, - $amount->getUnscaledBigInteger(), - $price, - $offerId - ); - } - - /** - * @return Asset - */ - public function getSellingAsset() - { - return $this->sellingAsset; - } - - /** - * @param Asset $sellingAsset - */ - public function setSellingAsset($sellingAsset) - { - $this->sellingAsset = $sellingAsset; - } - - /** - * @return Asset - */ - public function getBuyingAsset() - { - return $this->buyingAsset; - } - - /** - * @param Asset $buyingAsset - */ - public function setBuyingAsset($buyingAsset) - { - $this->buyingAsset = $buyingAsset; - } - - /** - * @return StellarAmount - */ - public function getAmount() - { - return $this->amount; - } - - /** - * @param int $amount - */ - public function setAmount($amount) - { - $this->amount = $amount; - } - - /** - * @return Price - */ - public function getPrice() - { - return $this->price; - } - - /** - * @param Price $price - */ - public function setPrice($price) - { - $this->price = $price; - } - - /** - * @return int - */ - public function getOfferId() - { - return $this->offerId; - } - - /** - * @param int $offerId - */ - public function setOfferId($offerId) - { - $this->offerId = $offerId; - } +sellingAsset = $sellingAsset; + $this->buyingAsset = $buyingAsset; + $this->amount = new StellarAmount($amount); + $this->price = $price; + $this->offerId = $offerId; + } + + /** + * @return string XDR bytes + */ + public function toXdr() + { + $bytes = parent::toXdr(); + + $bytes .= $this->sellingAsset->toXdr(); + $bytes .= $this->buyingAsset->toXdr(); + $bytes .= XdrEncoder::signedBigInteger64($this->amount->getUnscaledBigInteger()); + $bytes .= $this->price->toXdr(); + $bytes .= XdrEncoder::unsignedInteger64($this->offerId); + + return $bytes; + } + + /** + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return ManageOfferOp|Operation + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $sellingAsset = Asset::fromXdr($xdr); + $buyingAsset = Asset::fromXdr($xdr); + $amount = StellarAmount::fromXdr($xdr); + $price = Price::fromXdr($xdr); + $offerId = $xdr->readUnsignedInteger64(); + + return new ManageOfferOp($sellingAsset, + $buyingAsset, + $amount->getUnscaledBigInteger(), + $price, + $offerId + ); + } + + /** + * @return Asset + */ + public function getSellingAsset() + { + return $this->sellingAsset; + } + + /** + * @param Asset $sellingAsset + */ + public function setSellingAsset($sellingAsset) + { + $this->sellingAsset = $sellingAsset; + } + + /** + * @return Asset + */ + public function getBuyingAsset() + { + return $this->buyingAsset; + } + + /** + * @param Asset $buyingAsset + */ + public function setBuyingAsset($buyingAsset) + { + $this->buyingAsset = $buyingAsset; + } + + /** + * @return StellarAmount + */ + public function getAmount() + { + return $this->amount; + } + + /** + * @param int $amount + */ + public function setAmount($amount) + { + $this->amount = $amount; + } + + /** + * @return Price + */ + public function getPrice() + { + return $this->price; + } + + /** + * @param Price $price + */ + public function setPrice($price) + { + $this->price = $price; + } + + /** + * @return int + */ + public function getOfferId() + { + return $this->offerId; + } + + /** + * @param int $offerId + */ + public function setOfferId($offerId) + { + $this->offerId = $offerId; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/Operation.php b/src/XdrModel/Operation/Operation.php index c731726..b04b841 100755 --- a/src/XdrModel/Operation/Operation.php +++ b/src/XdrModel/Operation/Operation.php @@ -1,182 +1,182 @@ -getPublicKey()); - } - if (is_string($sourceAccountId)) { - $sourceAccountId = new AccountId($sourceAccountId); - } - - $this->sourceAccount = $sourceAccountId; - $this->type = $type; - - return $this; - } - - /** - * Child classes MUST call this method to get the header for the operation - * and then append their body - * - * @return string - */ - public function toXdr() - { - $bytes = ''; - - // Source Account - $bytes .= XdrEncoder::optional($this->sourceAccount); - - // Type - $bytes .= XdrEncoder::unsignedInteger($this->type); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return Operation - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - /** @var Operation $model */ - $model = null; - $hasSourceAccount = $xdr->readBoolean(); - - $sourceAccount = null; - if ($hasSourceAccount) { - $sourceAccount = AccountId::fromXdr($xdr); - } - - $type = $xdr->readUnsignedInteger(); - - switch ($type) { - case Operation::TYPE_CREATE_ACCOUNT: - $model = CreateAccountOp::fromXdr($xdr); - break; - case Operation::TYPE_PAYMENT: - $model = PaymentOp::fromXdr($xdr); - break; - case Operation::TYPE_PATH_PAYMENT: - $model = PathPaymentOp::fromXdr($xdr); - break; - case Operation::TYPE_MANAGE_OFFER: - $model = ManageOfferOp::fromXdr($xdr); - break; - case Operation::TYPE_CREATE_PASSIVE_OFFER: - $model = CreatePassiveOfferOp::fromXdr($xdr); - break; - case Operation::TYPE_SET_OPTIONS: - $model = SetOptionsOp::fromXdr($xdr); - break; - case Operation::TYPE_CHANGE_TRUST: - $model = ChangeTrustOp::fromXdr($xdr); - break; - case Operation::TYPE_ALLOW_TRUST: - $model = AllowTrustOp::fromXdr($xdr); - break; - case Operation::TYPE_ACCOUNT_MERGE: - $model = AccountMergeOp::fromXdr($xdr); - break; - case Operation::TYPE_INFLATION: - $model = new InflationOp(); // no additional XDR to parse - break; - case Operation::TYPE_MANAGE_DATA: - $model = ManageDataOp::fromXdr($xdr); - break; - case Operation::TYPE_BUMP_SEQUENCE: - $model = BumpSequenceOp::fromXdr($xdr); - break; - default: - throw new \InvalidArgumentException(sprintf('unrecognized operation type %s', $type)); - } - - $model->sourceAccount = $sourceAccount; - - return $model; - } - - /** - * @return AccountId - */ - public function getSourceAccount() - { - return $this->sourceAccount; - } - - /** - * @param AccountId $sourceAccount - */ - public function setSourceAccount(AccountId $sourceAccount) - { - $this->sourceAccount = $sourceAccount; - } +getPublicKey()); + } + if (is_string($sourceAccountId)) { + $sourceAccountId = new AccountId($sourceAccountId); + } + + $this->sourceAccount = $sourceAccountId; + $this->type = $type; + + return $this; + } + + /** + * Child classes MUST call this method to get the header for the operation + * and then append their body + * + * @return string + */ + public function toXdr() + { + $bytes = ''; + + // Source Account + $bytes .= XdrEncoder::optional($this->sourceAccount); + + // Type + $bytes .= XdrEncoder::unsignedInteger($this->type); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return Operation + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + /** @var Operation $model */ + $model = null; + $hasSourceAccount = $xdr->readBoolean(); + + $sourceAccount = null; + if ($hasSourceAccount) { + $sourceAccount = AccountId::fromXdr($xdr); + } + + $type = $xdr->readUnsignedInteger(); + + switch ($type) { + case Operation::TYPE_CREATE_ACCOUNT: + $model = CreateAccountOp::fromXdr($xdr); + break; + case Operation::TYPE_PAYMENT: + $model = PaymentOp::fromXdr($xdr); + break; + case Operation::TYPE_PATH_PAYMENT: + $model = PathPaymentOp::fromXdr($xdr); + break; + case Operation::TYPE_MANAGE_OFFER: + $model = ManageOfferOp::fromXdr($xdr); + break; + case Operation::TYPE_CREATE_PASSIVE_OFFER: + $model = CreatePassiveOfferOp::fromXdr($xdr); + break; + case Operation::TYPE_SET_OPTIONS: + $model = SetOptionsOp::fromXdr($xdr); + break; + case Operation::TYPE_CHANGE_TRUST: + $model = ChangeTrustOp::fromXdr($xdr); + break; + case Operation::TYPE_ALLOW_TRUST: + $model = AllowTrustOp::fromXdr($xdr); + break; + case Operation::TYPE_ACCOUNT_MERGE: + $model = AccountMergeOp::fromXdr($xdr); + break; + case Operation::TYPE_INFLATION: + $model = new InflationOp(); // no additional XDR to parse + break; + case Operation::TYPE_MANAGE_DATA: + $model = ManageDataOp::fromXdr($xdr); + break; + case Operation::TYPE_BUMP_SEQUENCE: + $model = BumpSequenceOp::fromXdr($xdr); + break; + default: + throw new \InvalidArgumentException(sprintf('unrecognized operation type %s', $type)); + } + + $model->sourceAccount = $sourceAccount; + + return $model; + } + + /** + * @return AccountId + */ + public function getSourceAccount() + { + return $this->sourceAccount; + } + + /** + * @param AccountId $sourceAccount + */ + public function setSourceAccount(AccountId $sourceAccount) + { + $this->sourceAccount = $sourceAccount; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/PathPaymentOp.php b/src/XdrModel/Operation/PathPaymentOp.php index 96d7f10..eced6f5 100644 --- a/src/XdrModel/Operation/PathPaymentOp.php +++ b/src/XdrModel/Operation/PathPaymentOp.php @@ -1,248 +1,248 @@ -getPublicKey(); - } - - $this->sendAsset = $sendAsset; - $this->sendMax = new StellarAmount($sendMax); - $this->destinationAccount = new AccountId($destinationAccountId); - $this->destinationAsset = $destinationAsset; - $this->destinationAmount = new StellarAmount($destinationAmount); - - $this->paths = new VariableArray(); - } - - /** - * @return string - * @throws \ErrorException - */ - public function toXdr() - { - $bytes = parent::toXdr(); - - // Sending asset - $bytes .= $this->sendAsset->toXdr(); - - // sendMax - $bytes .= XdrEncoder::signedBigInteger64($this->sendMax->getUnscaledBigInteger()); - - // Destination account - $bytes .= $this->destinationAccount->toXdr(); - - // Destination asset - $bytes .= $this->destinationAsset->toXdr(); - - // Destination amount - $bytes .= XdrEncoder::signedBigInteger64($this->destinationAmount->getUnscaledBigInteger()); - - // Paths - $bytes .= $this->paths->toXdr(); - - return $bytes; - } - - /** - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return Operation|PathPaymentOp - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $sendingAsset = Asset::fromXdr($xdr); - $sendMax = StellarAmount::fromXdr($xdr); - $destinationAccount = AccountId::fromXdr($xdr); - $destinationAsset = Asset::fromXdr($xdr); - $destinationAmount = StellarAmount::fromXdr($xdr); - - $model = new PathPaymentOp($sendingAsset, $sendMax->getUnscaledBigInteger(), $destinationAccount->getAccountIdString(), $destinationAsset, $destinationAmount->getUnscaledBigInteger()); - - $numPaths = $xdr->readUnsignedInteger(); - for ($i=0; $i < $numPaths; $i++) { - $model->paths->append(Asset::fromXdr($xdr)); - } - - return $model; - } - - /** - * @param Asset $path - * @return $this - */ - public function addPath(Asset $path) - { - // a maximum of 5 paths are supported - if (count($this->paths) >= 5) throw new \InvalidArgumentException('Too many paths: PathPaymentOp can contain a maximum of 5 paths'); - - $this->paths->append($path); - - return $this; - } - - /** - * @return Asset - */ - public function getSendAsset() - { - return $this->sendAsset; - } - - /** - * @param Asset $sendAsset - */ - public function setSendAsset($sendAsset) - { - $this->sendAsset = $sendAsset; - } - - /** - * @return StellarAmount - */ - public function getSendMax() - { - return $this->sendMax; - } - - /** - * @param number|BigInteger $sendMax number of XLM or BigInteger representing stroops - */ - public function setSendMax($sendMax) - { - $this->sendMax = new StellarAmount($sendMax); - } - - /** - * @return AccountId - */ - public function getDestinationAccount() - { - return $this->destinationAccount; - } - - /** - * @param AccountId $destinationAccount - */ - public function setDestinationAccount($destinationAccount) - { - $this->destinationAccount = $destinationAccount; - } - - /** - * @return Asset - */ - public function getDestinationAsset() - { - return $this->destinationAsset; - } - - /** - * @param Asset $destinationAsset - */ - public function setDestinationAsset($destinationAsset) - { - $this->destinationAsset = $destinationAsset; - } - - /** - * @return StellarAmount - */ - public function getDestinationAmount() - { - return $this->destinationAmount; - } - - /** - * @param number|BigInteger $destinationAmount number of XLM or BigInteger representing stroops - */ - public function setDestinationAmount($destinationAmount) - { - $this->destinationAmount = new StellarAmount($destinationAmount); - } - - /** - * @return Asset[] - */ - public function getPaths() - { - return $this->paths; - } - - /** - * @param Asset[] $paths - */ - public function setPaths($paths) - { - $this->paths = $paths; - } +getPublicKey(); + } + + $this->sendAsset = $sendAsset; + $this->sendMax = new StellarAmount($sendMax); + $this->destinationAccount = new AccountId($destinationAccountId); + $this->destinationAsset = $destinationAsset; + $this->destinationAmount = new StellarAmount($destinationAmount); + + $this->paths = new VariableArray(); + } + + /** + * @return string + * @throws \ErrorException + */ + public function toXdr() + { + $bytes = parent::toXdr(); + + // Sending asset + $bytes .= $this->sendAsset->toXdr(); + + // sendMax + $bytes .= XdrEncoder::signedBigInteger64($this->sendMax->getUnscaledBigInteger()); + + // Destination account + $bytes .= $this->destinationAccount->toXdr(); + + // Destination asset + $bytes .= $this->destinationAsset->toXdr(); + + // Destination amount + $bytes .= XdrEncoder::signedBigInteger64($this->destinationAmount->getUnscaledBigInteger()); + + // Paths + $bytes .= $this->paths->toXdr(); + + return $bytes; + } + + /** + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return Operation|PathPaymentOp + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $sendingAsset = Asset::fromXdr($xdr); + $sendMax = StellarAmount::fromXdr($xdr); + $destinationAccount = AccountId::fromXdr($xdr); + $destinationAsset = Asset::fromXdr($xdr); + $destinationAmount = StellarAmount::fromXdr($xdr); + + $model = new PathPaymentOp($sendingAsset, $sendMax->getUnscaledBigInteger(), $destinationAccount->getAccountIdString(), $destinationAsset, $destinationAmount->getUnscaledBigInteger()); + + $numPaths = $xdr->readUnsignedInteger(); + for ($i=0; $i < $numPaths; $i++) { + $model->paths->append(Asset::fromXdr($xdr)); + } + + return $model; + } + + /** + * @param Asset $path + * @return $this + */ + public function addPath(Asset $path) + { + // a maximum of 5 paths are supported + if (count($this->paths) >= 5) throw new \InvalidArgumentException('Too many paths: PathPaymentOp can contain a maximum of 5 paths'); + + $this->paths->append($path); + + return $this; + } + + /** + * @return Asset + */ + public function getSendAsset() + { + return $this->sendAsset; + } + + /** + * @param Asset $sendAsset + */ + public function setSendAsset($sendAsset) + { + $this->sendAsset = $sendAsset; + } + + /** + * @return StellarAmount + */ + public function getSendMax() + { + return $this->sendMax; + } + + /** + * @param number|BigInteger $sendMax number of XLM or BigInteger representing stroops + */ + public function setSendMax($sendMax) + { + $this->sendMax = new StellarAmount($sendMax); + } + + /** + * @return AccountId + */ + public function getDestinationAccount() + { + return $this->destinationAccount; + } + + /** + * @param AccountId $destinationAccount + */ + public function setDestinationAccount($destinationAccount) + { + $this->destinationAccount = $destinationAccount; + } + + /** + * @return Asset + */ + public function getDestinationAsset() + { + return $this->destinationAsset; + } + + /** + * @param Asset $destinationAsset + */ + public function setDestinationAsset($destinationAsset) + { + $this->destinationAsset = $destinationAsset; + } + + /** + * @return StellarAmount + */ + public function getDestinationAmount() + { + return $this->destinationAmount; + } + + /** + * @param number|BigInteger $destinationAmount number of XLM or BigInteger representing stroops + */ + public function setDestinationAmount($destinationAmount) + { + $this->destinationAmount = new StellarAmount($destinationAmount); + } + + /** + * @return Asset[] + */ + public function getPaths() + { + return $this->paths; + } + + /** + * @param Asset[] $paths + */ + public function setPaths($paths) + { + $this->paths = $paths; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/PaymentOp.php b/src/XdrModel/Operation/PaymentOp.php index 4b69510..ee860f7 100755 --- a/src/XdrModel/Operation/PaymentOp.php +++ b/src/XdrModel/Operation/PaymentOp.php @@ -1,170 +1,170 @@ -getPublicKey(); - } - - $op = new PaymentOp($sourceAccountId); - $op->destination = new AccountId($destinationAccountId); - $op->asset = Asset::newNativeAsset(); - $op->setAmount($amount); - - return $op; - } - - /** - * @param $destinationAccountId string|Keypair - * @param $amount - * @param $assetCode - * @param $assetIssuerId - * @param $sourceAccountId - * @return PaymentOp - */ - public static function newCustomPayment($destinationAccountId, $amount, $assetCode, $assetIssuerId, $sourceAccountId = null) - { - $op = new PaymentOp($sourceAccountId); - $op->destination = new AccountId($destinationAccountId); - $op->setAmount($amount); - $op->asset = Asset::newCustomAsset($assetCode, $assetIssuerId); - - return $op; - } - - /** - * PaymentOp constructor. - * - * @param null|string|Keypair $sourceAccount - */ - public function __construct($sourceAccount = null) - { - if (is_string($sourceAccount)) { - $sourceAccount = new AccountId($sourceAccount); - } - if ($sourceAccount instanceof Keypair) { - $sourceAccount = new AccountId($sourceAccount->getPublicKey()); - } - - parent::__construct(Operation::TYPE_PAYMENT, $sourceAccount); - } - - public function toXdr() - { - $bytes = parent::toXdr(); - - $bytes .= $this->destination->toXdr(); - $bytes .= $this->asset->toXdr(); - $bytes .= XdrEncoder::signedBigInteger64($this->amount->getUnscaledBigInteger()); - - return $bytes; - } - - /** - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return Operation|PaymentOp - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $op = new PaymentOp(); - - $op->destination = AccountId::fromXdr($xdr); - $op->asset = Asset::fromXdr($xdr); - $op->amount = StellarAmount::fromXdr($xdr); - - return $op; - } - - /** - * @param int|BigInteger $amount int representing lumens or BigInteger representing stroops - */ - public function setAmount($amount) - { - $this->amount = new StellarAmount($amount); - } - - /** - * @return StellarAmount - */ - public function getAmount() - { - return $this->amount; - } - - /** - * @param BigInteger $stroops - */ - public function setAmountInStroops(BigInteger $stroops) - { - $this->amount = new StellarAmount($stroops); - } - - /** - * @return AccountId - */ - public function getDestination() - { - return $this->destination; - } - - /** - * @param AccountId $destination - */ - public function setDestination($destination) - { - $this->destination = $destination; - } - - /** - * @return Asset - */ - public function getAsset() - { - return $this->asset; - } - - /** - * @param Asset $asset - */ - public function setAsset($asset) - { - $this->asset = $asset; - } +getPublicKey(); + } + + $op = new PaymentOp($sourceAccountId); + $op->destination = new AccountId($destinationAccountId); + $op->asset = Asset::newNativeAsset(); + $op->setAmount($amount); + + return $op; + } + + /** + * @param $destinationAccountId string|Keypair + * @param $amount + * @param $assetCode + * @param $assetIssuerId + * @param $sourceAccountId + * @return PaymentOp + */ + public static function newCustomPayment($destinationAccountId, $amount, $assetCode, $assetIssuerId, $sourceAccountId = null) + { + $op = new PaymentOp($sourceAccountId); + $op->destination = new AccountId($destinationAccountId); + $op->setAmount($amount); + $op->asset = Asset::newCustomAsset($assetCode, $assetIssuerId); + + return $op; + } + + /** + * PaymentOp constructor. + * + * @param null|string|Keypair $sourceAccount + */ + public function __construct($sourceAccount = null) + { + if (is_string($sourceAccount)) { + $sourceAccount = new AccountId($sourceAccount); + } + if ($sourceAccount instanceof Keypair) { + $sourceAccount = new AccountId($sourceAccount->getPublicKey()); + } + + parent::__construct(Operation::TYPE_PAYMENT, $sourceAccount); + } + + public function toXdr() + { + $bytes = parent::toXdr(); + + $bytes .= $this->destination->toXdr(); + $bytes .= $this->asset->toXdr(); + $bytes .= XdrEncoder::signedBigInteger64($this->amount->getUnscaledBigInteger()); + + return $bytes; + } + + /** + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return Operation|PaymentOp + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $op = new PaymentOp(); + + $op->destination = AccountId::fromXdr($xdr); + $op->asset = Asset::fromXdr($xdr); + $op->amount = StellarAmount::fromXdr($xdr); + + return $op; + } + + /** + * @param int|BigInteger $amount int representing lumens or BigInteger representing stroops + */ + public function setAmount($amount) + { + $this->amount = new StellarAmount($amount); + } + + /** + * @return StellarAmount + */ + public function getAmount() + { + return $this->amount; + } + + /** + * @param BigInteger $stroops + */ + public function setAmountInStroops(BigInteger $stroops) + { + $this->amount = new StellarAmount($stroops); + } + + /** + * @return AccountId + */ + public function getDestination() + { + return $this->destination; + } + + /** + * @param AccountId $destination + */ + public function setDestination($destination) + { + $this->destination = $destination; + } + + /** + * @return Asset + */ + public function getAsset() + { + return $this->asset; + } + + /** + * @param Asset $asset + */ + public function setAsset($asset) + { + $this->asset = $asset; + } } \ No newline at end of file diff --git a/src/XdrModel/Operation/SetOptionsOp.php b/src/XdrModel/Operation/SetOptionsOp.php index 1e3e8ff..bc24aa3 100755 --- a/src/XdrModel/Operation/SetOptionsOp.php +++ b/src/XdrModel/Operation/SetOptionsOp.php @@ -1,406 +1,406 @@ - - */ - private $homeDomain; - - /** - * @var Signer - */ - private $signer; - - /** - * @return SetOptionsOp - */ - public function __construct($sourceAccountId = null) - { - parent::__construct(Operation::TYPE_SET_OPTIONS, $sourceAccountId); - - $this->setFlags = null; - $this->clearFlags = null; - - return $this; - } - - public function toXdr() - { - $bytes = parent::toXdr(); - - // Treat 0 flags as null - if ($this->setFlags === 0) $this->setFlags = null; - if ($this->clearFlags === 0) $this->clearFlags = null; - - // inflation destination - $bytes .= XdrEncoder::optional($this->inflationDestinationAccount); - - // clear flags - $bytes .= XdrEncoder::optionalUnsignedInteger($this->clearFlags); - - // set flags - $bytes .= XdrEncoder::optionalUnsignedInteger($this->setFlags); - - // master weight - $bytes .= XdrEncoder::optionalUnsignedInteger($this->masterWeight); - - // low threshold - $bytes .= XdrEncoder::optionalUnsignedInteger($this->lowThreshold); - - // medium threshold - $bytes .= XdrEncoder::optionalUnsignedInteger($this->mediumThreshold); - - // high threshold - $bytes .= XdrEncoder::optionalUnsignedInteger($this->highThreshold); - - // home domain - $bytes .= XdrEncoder::optionalString($this->homeDomain, 32); - - // Signer - $bytes .= XdrEncoder::optional($this->signer); - - return $bytes; - } - - /** - * @deprecated Do not call this directly, instead call Operation::fromXdr() - * @param XdrBuffer $xdr - * @return Operation|SetOptionsOp - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $model = new SetOptionsOp(); - - // inflation destination - if ($xdr->readBoolean()) { - $model->inflationDestinationAccount = AccountId::fromXdr($xdr); - } - // clear flags - if ($xdr->readBoolean()) { - $model->applyClearFlags($xdr->readUnsignedInteger()); - } - // set flags - if ($xdr->readBoolean()) { - $model->applySetFlags($xdr->readUnsignedInteger()); - } - // master weight - if ($xdr->readBoolean()) { - $model->masterWeight = $xdr->readUnsignedInteger(); - } - // low threshold - if ($xdr->readBoolean()) { - $model->lowThreshold = $xdr->readUnsignedInteger(); - } - // medium threshold - if ($xdr->readBoolean()) { - $model->mediumThreshold = $xdr->readUnsignedInteger(); - } - // high threshold - if ($xdr->readBoolean()) { - $model->highThreshold = $xdr->readUnsignedInteger(); - } - // home domain - if ($xdr->readBoolean()) { - $model->homeDomain = $xdr->readString(32); - } - // signer - if ($xdr->readBoolean()) { - $model->signer = Signer::fromXdr($xdr); - } - - return $model; - } - - /** - * @param $accountId - * @return SetOptionsOp - */ - public function setInflationDestination($accountId) - { - $this->inflationDestinationAccount = new AccountId($accountId); - - return $this; - } - - /** - * If set, TrustLines are created with authorized set to false requiring the issuer to set it for each TrustLine - * - * @param $isRequired - * @return SetOptionsOp - */ - public function setAuthRequired($isRequired) - { - if ($isRequired) { - $this->setFlags = $this->setFlags | static::FLAG_AUTH_REQUIRED; - $this->clearFlags = $this->clearFlags & ~(static::FLAG_AUTH_REQUIRED); - } - else { - $this->setFlags = $this->setFlags & ~(static::FLAG_AUTH_REQUIRED); - $this->clearFlags = $this->clearFlags | static::FLAG_AUTH_REQUIRED; - } - - return $this; - } - - /** - * @return bool - */ - public function isAuthRequired() - { - return boolval($this->setFlags & static::FLAG_AUTH_REQUIRED); - } - - /** - * If set, the authorized flag in TrustLines can be cleared. Otherwise, authorization cannot be revoked - * - * @param $isRevocable - * @return SetOptionsOp - */ - public function setAuthRevocable($isRevocable) - { - if ($isRevocable) { - $this->setFlags = $this->setFlags | static::FLAG_AUTH_REVOCABLE; - $this->clearFlags = $this->clearFlags & ~(static::FLAG_AUTH_REVOCABLE); - } - else { - $this->setFlags = $this->setFlags & ~(static::FLAG_AUTH_REVOCABLE); - $this->clearFlags = $this->clearFlags | static::FLAG_AUTH_REVOCABLE; - } - - return $this; - } - - /** - * @return bool - */ - public function isAuthRevocable() - { - return boolval($this->setFlags & static::FLAG_AUTH_REVOCABLE); - } - - /** - * Set the weight of $signer to 0 to remove it - * - * @param Signer $signer - * @return SetOptionsOp - */ - public function updateSigner(Signer $signer) - { - $this->signer = $signer; - - return $this; - } - - /** - * @param $weight - * @return SetOptionsOp - */ - public function setMasterWeight($weight) - { - if ($weight > 255 || $weight < 0) throw new \InvalidArgumentException('$weight must be between 0 and 255'); - - $this->masterWeight = $weight; - - return $this; - } - - /** - * @param $threshold - * @return $this - */ - public function setLowThreshold($threshold) - { - if ($threshold < 0 || $threshold > 255) throw new \InvalidArgumentException('$threshold must be between 0 and ' . (2^32-1)); - - $this->lowThreshold = $threshold; - - return $this; - } - - /** - * @param $threshold - * @return $this - */ - public function setMediumThreshold($threshold) - { - if ($threshold < 0 || $threshold > 255) throw new \InvalidArgumentException('$threshold must be between 0 and ' . (2^32-1)); - - $this->mediumThreshold = $threshold; - - return $this; - } - - /** - * @param $threshold - * @return $this - */ - public function setHighThreshold($threshold) - { - if ($threshold < 0 || $threshold > 255) throw new \InvalidArgumentException('$threshold must be between 0 and ' . (2^32-1)); - - $this->highThreshold = $threshold; - - return $this; - } - - /** - * @param $domain string maximum length 32 characters - * @return $this - */ - public function setHomeDomain($domain) - { - if (strlen($domain) > 32) throw new \InvalidArgumentException('$domain can not be longer than 32 characters'); - - $this->homeDomain = $domain; - - return $this; - } - - /** - * @return AccountId - */ - public function getInflationDestinationAccount() - { - return $this->inflationDestinationAccount; - } - - /** - * @return int - */ - public function getClearFlags() - { - return $this->clearFlags; - } - - /** - * @return int - */ - public function getSetFlags() - { - return $this->setFlags; - } - - /** - * @return int - */ - public function getMasterWeight() - { - return $this->masterWeight; - } - - /** - * @return int - */ - public function getLowThreshold() - { - return $this->lowThreshold; - } - - /** - * @return int - */ - public function getMediumThreshold() - { - return $this->mediumThreshold; - } - - /** - * @return int - */ - public function getHighThreshold() - { - return $this->highThreshold; - } - - /** - * @return string - */ - public function getHomeDomain() - { - return $this->homeDomain; - } - - /** - * @return Signer - */ - public function getSigner() - { - return $this->signer; - } - - /** - * @param $clearFlags - */ - protected function applyClearFlags($clearFlags) - { - if ($clearFlags & static::FLAG_AUTH_REQUIRED) { - $this->setAuthRequired(false); - } - if ($clearFlags & static::FLAG_AUTH_REVOCABLE) { - $this->setAuthRevocable(false); - } - } - - /** - * @param $setFlags - */ - protected function applySetFlags($setFlags) - { - if ($setFlags & static::FLAG_AUTH_REQUIRED) { - $this->setAuthRequired(true); - } - if ($setFlags & static::FLAG_AUTH_REVOCABLE) { - $this->setAuthRevocable(true); - } - } + + */ + private $homeDomain; + + /** + * @var Signer + */ + private $signer; + + /** + * @return SetOptionsOp + */ + public function __construct($sourceAccountId = null) + { + parent::__construct(Operation::TYPE_SET_OPTIONS, $sourceAccountId); + + $this->setFlags = null; + $this->clearFlags = null; + + return $this; + } + + public function toXdr() + { + $bytes = parent::toXdr(); + + // Treat 0 flags as null + if ($this->setFlags === 0) $this->setFlags = null; + if ($this->clearFlags === 0) $this->clearFlags = null; + + // inflation destination + $bytes .= XdrEncoder::optional($this->inflationDestinationAccount); + + // clear flags + $bytes .= XdrEncoder::optionalUnsignedInteger($this->clearFlags); + + // set flags + $bytes .= XdrEncoder::optionalUnsignedInteger($this->setFlags); + + // master weight + $bytes .= XdrEncoder::optionalUnsignedInteger($this->masterWeight); + + // low threshold + $bytes .= XdrEncoder::optionalUnsignedInteger($this->lowThreshold); + + // medium threshold + $bytes .= XdrEncoder::optionalUnsignedInteger($this->mediumThreshold); + + // high threshold + $bytes .= XdrEncoder::optionalUnsignedInteger($this->highThreshold); + + // home domain + $bytes .= XdrEncoder::optionalString($this->homeDomain, 32); + + // Signer + $bytes .= XdrEncoder::optional($this->signer); + + return $bytes; + } + + /** + * @deprecated Do not call this directly, instead call Operation::fromXdr() + * @param XdrBuffer $xdr + * @return Operation|SetOptionsOp + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $model = new SetOptionsOp(); + + // inflation destination + if ($xdr->readBoolean()) { + $model->inflationDestinationAccount = AccountId::fromXdr($xdr); + } + // clear flags + if ($xdr->readBoolean()) { + $model->applyClearFlags($xdr->readUnsignedInteger()); + } + // set flags + if ($xdr->readBoolean()) { + $model->applySetFlags($xdr->readUnsignedInteger()); + } + // master weight + if ($xdr->readBoolean()) { + $model->masterWeight = $xdr->readUnsignedInteger(); + } + // low threshold + if ($xdr->readBoolean()) { + $model->lowThreshold = $xdr->readUnsignedInteger(); + } + // medium threshold + if ($xdr->readBoolean()) { + $model->mediumThreshold = $xdr->readUnsignedInteger(); + } + // high threshold + if ($xdr->readBoolean()) { + $model->highThreshold = $xdr->readUnsignedInteger(); + } + // home domain + if ($xdr->readBoolean()) { + $model->homeDomain = $xdr->readString(32); + } + // signer + if ($xdr->readBoolean()) { + $model->signer = Signer::fromXdr($xdr); + } + + return $model; + } + + /** + * @param $accountId + * @return SetOptionsOp + */ + public function setInflationDestination($accountId) + { + $this->inflationDestinationAccount = new AccountId($accountId); + + return $this; + } + + /** + * If set, TrustLines are created with authorized set to false requiring the issuer to set it for each TrustLine + * + * @param $isRequired + * @return SetOptionsOp + */ + public function setAuthRequired($isRequired) + { + if ($isRequired) { + $this->setFlags = $this->setFlags | static::FLAG_AUTH_REQUIRED; + $this->clearFlags = $this->clearFlags & ~(static::FLAG_AUTH_REQUIRED); + } + else { + $this->setFlags = $this->setFlags & ~(static::FLAG_AUTH_REQUIRED); + $this->clearFlags = $this->clearFlags | static::FLAG_AUTH_REQUIRED; + } + + return $this; + } + + /** + * @return bool + */ + public function isAuthRequired() + { + return boolval($this->setFlags & static::FLAG_AUTH_REQUIRED); + } + + /** + * If set, the authorized flag in TrustLines can be cleared. Otherwise, authorization cannot be revoked + * + * @param $isRevocable + * @return SetOptionsOp + */ + public function setAuthRevocable($isRevocable) + { + if ($isRevocable) { + $this->setFlags = $this->setFlags | static::FLAG_AUTH_REVOCABLE; + $this->clearFlags = $this->clearFlags & ~(static::FLAG_AUTH_REVOCABLE); + } + else { + $this->setFlags = $this->setFlags & ~(static::FLAG_AUTH_REVOCABLE); + $this->clearFlags = $this->clearFlags | static::FLAG_AUTH_REVOCABLE; + } + + return $this; + } + + /** + * @return bool + */ + public function isAuthRevocable() + { + return boolval($this->setFlags & static::FLAG_AUTH_REVOCABLE); + } + + /** + * Set the weight of $signer to 0 to remove it + * + * @param Signer $signer + * @return SetOptionsOp + */ + public function updateSigner(Signer $signer) + { + $this->signer = $signer; + + return $this; + } + + /** + * @param $weight + * @return SetOptionsOp + */ + public function setMasterWeight($weight) + { + if ($weight > 255 || $weight < 0) throw new \InvalidArgumentException('$weight must be between 0 and 255'); + + $this->masterWeight = $weight; + + return $this; + } + + /** + * @param $threshold + * @return $this + */ + public function setLowThreshold($threshold) + { + if ($threshold < 0 || $threshold > 255) throw new \InvalidArgumentException('$threshold must be between 0 and ' . (2^32-1)); + + $this->lowThreshold = $threshold; + + return $this; + } + + /** + * @param $threshold + * @return $this + */ + public function setMediumThreshold($threshold) + { + if ($threshold < 0 || $threshold > 255) throw new \InvalidArgumentException('$threshold must be between 0 and ' . (2^32-1)); + + $this->mediumThreshold = $threshold; + + return $this; + } + + /** + * @param $threshold + * @return $this + */ + public function setHighThreshold($threshold) + { + if ($threshold < 0 || $threshold > 255) throw new \InvalidArgumentException('$threshold must be between 0 and ' . (2^32-1)); + + $this->highThreshold = $threshold; + + return $this; + } + + /** + * @param $domain string maximum length 32 characters + * @return $this + */ + public function setHomeDomain($domain) + { + if (strlen($domain) > 32) throw new \InvalidArgumentException('$domain can not be longer than 32 characters'); + + $this->homeDomain = $domain; + + return $this; + } + + /** + * @return AccountId + */ + public function getInflationDestinationAccount() + { + return $this->inflationDestinationAccount; + } + + /** + * @return int + */ + public function getClearFlags() + { + return $this->clearFlags; + } + + /** + * @return int + */ + public function getSetFlags() + { + return $this->setFlags; + } + + /** + * @return int + */ + public function getMasterWeight() + { + return $this->masterWeight; + } + + /** + * @return int + */ + public function getLowThreshold() + { + return $this->lowThreshold; + } + + /** + * @return int + */ + public function getMediumThreshold() + { + return $this->mediumThreshold; + } + + /** + * @return int + */ + public function getHighThreshold() + { + return $this->highThreshold; + } + + /** + * @return string + */ + public function getHomeDomain() + { + return $this->homeDomain; + } + + /** + * @return Signer + */ + public function getSigner() + { + return $this->signer; + } + + /** + * @param $clearFlags + */ + protected function applyClearFlags($clearFlags) + { + if ($clearFlags & static::FLAG_AUTH_REQUIRED) { + $this->setAuthRequired(false); + } + if ($clearFlags & static::FLAG_AUTH_REVOCABLE) { + $this->setAuthRevocable(false); + } + } + + /** + * @param $setFlags + */ + protected function applySetFlags($setFlags) + { + if ($setFlags & static::FLAG_AUTH_REQUIRED) { + $this->setAuthRequired(true); + } + if ($setFlags & static::FLAG_AUTH_REVOCABLE) { + $this->setAuthRevocable(true); + } + } } \ No newline at end of file diff --git a/src/XdrModel/OperationResult.php b/src/XdrModel/OperationResult.php index e519a03..6245caf 100644 --- a/src/XdrModel/OperationResult.php +++ b/src/XdrModel/OperationResult.php @@ -1,118 +1,118 @@ -readInteger(); - - // Early return for operations that failed - if ($opResultCode === -1) { - $opResult = new OperationResult(); - $opResult->errorCode = static::BAD_AUTH; - - return $opResult; - } - if ($opResultCode === -2) { - $opResult = new OperationResult(); - $opResult->errorCode = static::NO_ACCOUNT; - - return $opResult; - } - - // Past this point there can be a variety of operation results - $opType = $xdr->readInteger(); - switch ($opType) { - case Operation::TYPE_CREATE_ACCOUNT: - return CreateAccountResult::fromXdr($xdr); - break; - case Operation::TYPE_PAYMENT: - return PaymentResult::fromXdr($xdr); - break; - case Operation::TYPE_PATH_PAYMENT; - return PathPaymentResult::fromXdr($xdr); - break; - case Operation::TYPE_MANAGE_OFFER: - return ManageOfferResult::fromXdr($xdr); - break; - case Operation::TYPE_SET_OPTIONS: - return SetOptionsResult::fromXdr($xdr); - break; - case Operation::TYPE_CHANGE_TRUST: - return ChangeTrustResult::fromXdr($xdr); - break; - case Operation::TYPE_ALLOW_TRUST: - return AllowTrustResult::fromXdr($xdr); - break; - case Operation::TYPE_ACCOUNT_MERGE: - return AccountMergeResult::fromXdr($xdr); - break; - case Operation::TYPE_INFLATION: - return InflationResult::fromXdr($xdr); - break; - case Operation::TYPE_MANAGE_DATA: - return ManageDataResult::fromXdr($xdr); - break; - case Operation::TYPE_BUMP_SEQUENCE: - return BumpSequenceResult::fromXdr($xdr); - break; - default: - throw new \ErrorException(sprintf('Unknown operation type: %s', $opType)); - } - } - - public function __construct() - { - $this->errorCode = null; - } - - /** - * Returns true if this operation succeeded - * - * @return bool - */ - public function succeeded() - { - return $this->errorCode === null; - } - - /** - * Returns true if this operation failed - * - * @return bool - */ - public function failed() - { - return !$this->succeeded(); - } - - /** - * @return null|string - */ - public function getErrorCode() - { - return $this->errorCode; - } +readInteger(); + + // Early return for operations that failed + if ($opResultCode === -1) { + $opResult = new OperationResult(); + $opResult->errorCode = static::BAD_AUTH; + + return $opResult; + } + if ($opResultCode === -2) { + $opResult = new OperationResult(); + $opResult->errorCode = static::NO_ACCOUNT; + + return $opResult; + } + + // Past this point there can be a variety of operation results + $opType = $xdr->readInteger(); + switch ($opType) { + case Operation::TYPE_CREATE_ACCOUNT: + return CreateAccountResult::fromXdr($xdr); + break; + case Operation::TYPE_PAYMENT: + return PaymentResult::fromXdr($xdr); + break; + case Operation::TYPE_PATH_PAYMENT; + return PathPaymentResult::fromXdr($xdr); + break; + case Operation::TYPE_MANAGE_OFFER: + return ManageOfferResult::fromXdr($xdr); + break; + case Operation::TYPE_SET_OPTIONS: + return SetOptionsResult::fromXdr($xdr); + break; + case Operation::TYPE_CHANGE_TRUST: + return ChangeTrustResult::fromXdr($xdr); + break; + case Operation::TYPE_ALLOW_TRUST: + return AllowTrustResult::fromXdr($xdr); + break; + case Operation::TYPE_ACCOUNT_MERGE: + return AccountMergeResult::fromXdr($xdr); + break; + case Operation::TYPE_INFLATION: + return InflationResult::fromXdr($xdr); + break; + case Operation::TYPE_MANAGE_DATA: + return ManageDataResult::fromXdr($xdr); + break; + case Operation::TYPE_BUMP_SEQUENCE: + return BumpSequenceResult::fromXdr($xdr); + break; + default: + throw new \ErrorException(sprintf('Unknown operation type: %s', $opType)); + } + } + + public function __construct() + { + $this->errorCode = null; + } + + /** + * Returns true if this operation succeeded + * + * @return bool + */ + public function succeeded() + { + return $this->errorCode === null; + } + + /** + * Returns true if this operation failed + * + * @return bool + */ + public function failed() + { + return !$this->succeeded(); + } + + /** + * @return null|string + */ + public function getErrorCode() + { + return $this->errorCode; + } } \ No newline at end of file diff --git a/src/XdrModel/PathPaymentResult.php b/src/XdrModel/PathPaymentResult.php index 784d7f4..9bb0738 100644 --- a/src/XdrModel/PathPaymentResult.php +++ b/src/XdrModel/PathPaymentResult.php @@ -1,169 +1,169 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::MALFORMED, - '-2' => static::UNDERFUNDED, - '-3' => static::SRC_NO_TRUST, - '-4' => static::SRC_NOT_AUTHORIZED, - '-5' => static::NO_DESTINATION, - '-6' => static::NO_TRUST, - '-7' => static::NOT_AUTHORIZED, - '-8' => static::LINE_FULL, - '-9' => static::NO_ISSUER, - '-10' => static::TOO_FEW_OFFERS, - '-11' => static::OFFER_CROSS_SELF, - '-12' => static::OVER_SENDMAX, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - } - - // special case: a "no issuer" error code means we need to parse a different - // value from the XDR - if ($errorCodeMap[$rawErrorCode] == self::NO_ISSUER) { - $model->paidAsset = Asset::fromXdr($xdr); - } - // Normal XDR parsing https://github.com/stellar/stellar-core/blob/3c4e356803175f6c2645e4437881cf07522df94d/src/xdr/Stellar-transaction.x#L441 - else { - $numOffersClaimed = $xdr->readUnsignedInteger(); - for ($i=0; $i < $numOffersClaimed; $i++) { - $model->claimedOffers[] = ClaimOfferAtom::fromXdr($xdr); - } - - // These fields are combined into a SimplePaymentResult in the XDR spec, - // but it only appears to be used in one place so I'm leaving them as - // separate fields for now - $model->destination = AccountId::fromXdr($xdr); - $model->paidAsset = Asset::fromXdr($xdr); - $model->paidAmount = new StellarAmount(new BigInteger($xdr->readInteger64())); - } - - return $model; - } - - /** - * @return ClaimOfferAtom[] - */ - public function getClaimedOffers() - { - return $this->claimedOffers; - } - - /** - * @param ClaimOfferAtom[] $claimedOffers - */ - public function setClaimedOffers($claimedOffers) - { - $this->claimedOffers = $claimedOffers; - } - - /** - * @return AccountId - */ - public function getDestination() - { - return $this->destination; - } - - /** - * @param AccountId $destination - */ - public function setDestination($destination) - { - $this->destination = $destination; - } - - /** - * @return Asset - */ - public function getPaidAsset() - { - return $this->paidAsset; - } - - /** - * @param Asset $paidAsset - */ - public function setPaidAsset($paidAsset) - { - $this->paidAsset = $paidAsset; - } - - /** - * @return StellarAmount - */ - public function getPaidAmount() - { - return $this->paidAmount; - } - - /** - * @param StellarAmount $paidAmount - */ - public function setPaidAmount($paidAmount) - { - $this->paidAmount = $paidAmount; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::MALFORMED, + '-2' => static::UNDERFUNDED, + '-3' => static::SRC_NO_TRUST, + '-4' => static::SRC_NOT_AUTHORIZED, + '-5' => static::NO_DESTINATION, + '-6' => static::NO_TRUST, + '-7' => static::NOT_AUTHORIZED, + '-8' => static::LINE_FULL, + '-9' => static::NO_ISSUER, + '-10' => static::TOO_FEW_OFFERS, + '-11' => static::OFFER_CROSS_SELF, + '-12' => static::OVER_SENDMAX, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + } + + // special case: a "no issuer" error code means we need to parse a different + // value from the XDR + if ($errorCodeMap[$rawErrorCode] == self::NO_ISSUER) { + $model->paidAsset = Asset::fromXdr($xdr); + } + // Normal XDR parsing https://github.com/stellar/stellar-core/blob/3c4e356803175f6c2645e4437881cf07522df94d/src/xdr/Stellar-transaction.x#L441 + else { + $numOffersClaimed = $xdr->readUnsignedInteger(); + for ($i=0; $i < $numOffersClaimed; $i++) { + $model->claimedOffers[] = ClaimOfferAtom::fromXdr($xdr); + } + + // These fields are combined into a SimplePaymentResult in the XDR spec, + // but it only appears to be used in one place so I'm leaving them as + // separate fields for now + $model->destination = AccountId::fromXdr($xdr); + $model->paidAsset = Asset::fromXdr($xdr); + $model->paidAmount = new StellarAmount(new BigInteger($xdr->readInteger64())); + } + + return $model; + } + + /** + * @return ClaimOfferAtom[] + */ + public function getClaimedOffers() + { + return $this->claimedOffers; + } + + /** + * @param ClaimOfferAtom[] $claimedOffers + */ + public function setClaimedOffers($claimedOffers) + { + $this->claimedOffers = $claimedOffers; + } + + /** + * @return AccountId + */ + public function getDestination() + { + return $this->destination; + } + + /** + * @param AccountId $destination + */ + public function setDestination($destination) + { + $this->destination = $destination; + } + + /** + * @return Asset + */ + public function getPaidAsset() + { + return $this->paidAsset; + } + + /** + * @param Asset $paidAsset + */ + public function setPaidAsset($paidAsset) + { + $this->paidAsset = $paidAsset; + } + + /** + * @return StellarAmount + */ + public function getPaidAmount() + { + return $this->paidAmount; + } + + /** + * @param StellarAmount $paidAmount + */ + public function setPaidAmount($paidAmount) + { + $this->paidAmount = $paidAmount; + } } \ No newline at end of file diff --git a/src/XdrModel/PaymentResult.php b/src/XdrModel/PaymentResult.php index 1c46f3b..dc598a5 100644 --- a/src/XdrModel/PaymentResult.php +++ b/src/XdrModel/PaymentResult.php @@ -1,57 +1,57 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::MALFORMED, - '-2' => static::UNDERFUNDED, - '-3' => static::SRC_NO_TRUST, - '-4' => static::SRC_NOT_AUTHORIZED, - '-5' => static::NO_DESTINATION, - '-6' => static::NO_TRUST, - '-7' => static::NOT_AUTHORIZED, - '-8' => static::LINE_FULL, - '-9' => static::NO_ISSUER, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - } - - return $model; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::MALFORMED, + '-2' => static::UNDERFUNDED, + '-3' => static::SRC_NO_TRUST, + '-4' => static::SRC_NOT_AUTHORIZED, + '-5' => static::NO_DESTINATION, + '-6' => static::NO_TRUST, + '-7' => static::NOT_AUTHORIZED, + '-8' => static::LINE_FULL, + '-9' => static::NO_ISSUER, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + } + + return $model; + } } \ No newline at end of file diff --git a/src/XdrModel/Price.php b/src/XdrModel/Price.php index a83ae3c..6bd4bba 100644 --- a/src/XdrModel/Price.php +++ b/src/XdrModel/Price.php @@ -1,101 +1,101 @@ -numerator = $numerator; - $this->denominator = $denominator; - } - - public function __toString() - { - return strval($this->numerator / $this->denominator); - } - - public function toXdr() - { - $bytes = ''; - - $bytes .= XdrEncoder::unsignedInteger($this->numerator); - $bytes .= XdrEncoder::unsignedInteger($this->denominator); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return Price - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $numerator = $xdr->readUnsignedInteger(); - $denominator = $xdr->readUnsignedInteger(); - - return new Price($numerator, $denominator); - } - - /** - * @return float - */ - public function toFloat() - { - return floatval($this->numerator / $this->denominator); - } - - /** - * @return int - */ - public function getNumerator() - { - return $this->numerator; - } - - /** - * @param int $numerator - */ - public function setNumerator($numerator) - { - $this->numerator = $numerator; - } - - /** - * @return int - */ - public function getDenominator() - { - return $this->denominator; - } - - /** - * @param int $denominator - */ - public function setDenominator($denominator) - { - $this->denominator = $denominator; - } +numerator = $numerator; + $this->denominator = $denominator; + } + + public function __toString() + { + return strval($this->numerator / $this->denominator); + } + + public function toXdr() + { + $bytes = ''; + + $bytes .= XdrEncoder::unsignedInteger($this->numerator); + $bytes .= XdrEncoder::unsignedInteger($this->denominator); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return Price + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $numerator = $xdr->readUnsignedInteger(); + $denominator = $xdr->readUnsignedInteger(); + + return new Price($numerator, $denominator); + } + + /** + * @return float + */ + public function toFloat() + { + return floatval($this->numerator / $this->denominator); + } + + /** + * @return int + */ + public function getNumerator() + { + return $this->numerator; + } + + /** + * @param int $numerator + */ + public function setNumerator($numerator) + { + $this->numerator = $numerator; + } + + /** + * @return int + */ + public function getDenominator() + { + return $this->denominator; + } + + /** + * @param int $denominator + */ + public function setDenominator($denominator) + { + $this->denominator = $denominator; + } } \ No newline at end of file diff --git a/src/XdrModel/SetOptionsResult.php b/src/XdrModel/SetOptionsResult.php index 1de825d..611f7b3 100644 --- a/src/XdrModel/SetOptionsResult.php +++ b/src/XdrModel/SetOptionsResult.php @@ -1,57 +1,57 @@ -readInteger(); - $errorCodeMap = [ - '0' => 'success', - '-1' => static::LOW_RESERVE, - '-2' => static::TOO_MANY_SIGNERS, - '-3' => static::BAD_FLAGS, - '-4' => static::INVALID_INFLATION, - '-5' => static::CANT_CHANGE, - '-6' => static::UNKNOWN_FLAG, - '-7' => static::THRESHOLD_OUT_OF_RANGE, - '-8' => static::BAD_SIGNER, - '-9' => static::INVALID_HOME_DOMAIN, - ]; - if (!isset($errorCodeMap[$rawErrorCode])) { - throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); - } - - // Do not store the "success" error code - if ($errorCodeMap[$rawErrorCode] !== 'success') { - $model->errorCode = $errorCodeMap[$rawErrorCode]; - } - - return $model; - } +readInteger(); + $errorCodeMap = [ + '0' => 'success', + '-1' => static::LOW_RESERVE, + '-2' => static::TOO_MANY_SIGNERS, + '-3' => static::BAD_FLAGS, + '-4' => static::INVALID_INFLATION, + '-5' => static::CANT_CHANGE, + '-6' => static::UNKNOWN_FLAG, + '-7' => static::THRESHOLD_OUT_OF_RANGE, + '-8' => static::BAD_SIGNER, + '-9' => static::INVALID_HOME_DOMAIN, + ]; + if (!isset($errorCodeMap[$rawErrorCode])) { + throw new \ErrorException(sprintf('Unknown error code %s', $rawErrorCode)); + } + + // Do not store the "success" error code + if ($errorCodeMap[$rawErrorCode] !== 'success') { + $model->errorCode = $errorCodeMap[$rawErrorCode]; + } + + return $model; + } } \ No newline at end of file diff --git a/src/XdrModel/Signer.php b/src/XdrModel/Signer.php index 8c21730..acd438a 100755 --- a/src/XdrModel/Signer.php +++ b/src/XdrModel/Signer.php @@ -1,93 +1,93 @@ -key = $key; - $this->weight = $weight; - } - - public function toXdr() - { - $bytes = ''; - - // key - $bytes .= $this->key->toXdr(); - - // weight - $bytes .= XdrEncoder::unsignedInteger($this->weight); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return Signer - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $signerKey = SignerKey::fromXdr($xdr); - $weight = $xdr->readUnsignedInteger(); - - return new Signer($signerKey, $weight); - } - - /** - * @return SignerKey - */ - public function getKey() - { - return $this->key; - } - - /** - * @param SignerKey $key - */ - public function setKey($key) - { - $this->key = $key; - } - - /** - * @return int - */ - public function getWeight() - { - return $this->weight; - } - - /** - * @param int $weight - */ - public function setWeight($weight) - { - if ($weight > 255 || $weight < 0) throw new \InvalidArgumentException('weight must be between 0 and 255'); - - $this->weight = $weight; - } +key = $key; + $this->weight = $weight; + } + + public function toXdr() + { + $bytes = ''; + + // key + $bytes .= $this->key->toXdr(); + + // weight + $bytes .= XdrEncoder::unsignedInteger($this->weight); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return Signer + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $signerKey = SignerKey::fromXdr($xdr); + $weight = $xdr->readUnsignedInteger(); + + return new Signer($signerKey, $weight); + } + + /** + * @return SignerKey + */ + public function getKey() + { + return $this->key; + } + + /** + * @param SignerKey $key + */ + public function setKey($key) + { + $this->key = $key; + } + + /** + * @return int + */ + public function getWeight() + { + return $this->weight; + } + + /** + * @param int $weight + */ + public function setWeight($weight) + { + if ($weight > 255 || $weight < 0) throw new \InvalidArgumentException('weight must be between 0 and 255'); + + $this->weight = $weight; + } } \ No newline at end of file diff --git a/src/XdrModel/SignerKey.php b/src/XdrModel/SignerKey.php index 56bd36a..9b2a9f7 100755 --- a/src/XdrModel/SignerKey.php +++ b/src/XdrModel/SignerKey.php @@ -1,124 +1,124 @@ -key = $keypair->getPublicKeyBytes(); - - return $signerKey; - } - - /** - * @param $hashBytes - * @return SignerKey - */ - public static function fromPreauthorizedHash($hashBytes) - { - if (strlen($hashBytes) != 32) { - throw new \InvalidArgumentException('$hashBytes must be 32 bytes representing the sha256 hash of the transaction'); - } - - $signerKey = new SignerKey(static::TYPE_PRE_AUTH_TX); - $signerKey->key = $hashBytes; - - return $signerKey; - } - - /** - * Adds the value of $x as a signer on the account - * - * @param $x - * @return SignerKey - */ - public static function fromHashX($x) - { - $signerKey = new SignerKey(static::TYPE_HASH_X); - $signerKey->key = hash('sha256', $x, true); - - return $signerKey; - } - - public function __construct($type) - { - $this->type = $type; - } - - public function toXdr() - { - $bytes = ''; - - // Type - $bytes .= XdrEncoder::unsignedInteger($this->type); - - // Key - $bytes .= XdrEncoder::unsignedInteger256($this->key); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return SignerKey - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $type = $xdr->readUnsignedInteger(); - $model = new SignerKey($type); - - $model->key = $xdr->readOpaqueFixed(32); - - return $model; - } - - /** - * @return int - */ - public function getType() - { - return $this->type; - } - - /** - * @return string - */ - public function getKey() - { - return $this->key; - } +key = $keypair->getPublicKeyBytes(); + + return $signerKey; + } + + /** + * @param $hashBytes + * @return SignerKey + */ + public static function fromPreauthorizedHash($hashBytes) + { + if (strlen($hashBytes) != 32) { + throw new \InvalidArgumentException('$hashBytes must be 32 bytes representing the sha256 hash of the transaction'); + } + + $signerKey = new SignerKey(static::TYPE_PRE_AUTH_TX); + $signerKey->key = $hashBytes; + + return $signerKey; + } + + /** + * Adds the value of $x as a signer on the account + * + * @param $x + * @return SignerKey + */ + public static function fromHashX($x) + { + $signerKey = new SignerKey(static::TYPE_HASH_X); + $signerKey->key = hash('sha256', $x, true); + + return $signerKey; + } + + public function __construct($type) + { + $this->type = $type; + } + + public function toXdr() + { + $bytes = ''; + + // Type + $bytes .= XdrEncoder::unsignedInteger($this->type); + + // Key + $bytes .= XdrEncoder::unsignedInteger256($this->key); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return SignerKey + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $type = $xdr->readUnsignedInteger(); + $model = new SignerKey($type); + + $model->key = $xdr->readOpaqueFixed(32); + + return $model; + } + + /** + * @return int + */ + public function getType() + { + return $this->type; + } + + /** + * @return string + */ + public function getKey() + { + return $this->key; + } } \ No newline at end of file diff --git a/src/XdrModel/TimeBounds.php b/src/XdrModel/TimeBounds.php index a3e6e04..786199f 100755 --- a/src/XdrModel/TimeBounds.php +++ b/src/XdrModel/TimeBounds.php @@ -1,123 +1,123 @@ -minTime = $minTime; - $this->maxTime = $maxTime; - } - - /** - * @param \DateTime $min - */ - public function setMinTime(\DateTime $min) - { - $this->minTime = clone $min; - } - - /** - * @param \DateTime $max - */ - public function setMaxTime(\DateTime $max) - { - $this->maxTime = clone $max; - } - - public function toXdr() - { - $bytes = ''; - - $bytes .= XdrEncoder::unsignedInteger64($this->getMinTimestamp()); - $bytes .= XdrEncoder::unsignedInteger64($this->getMaxTimestamp()); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return null|TimeBounds - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $model = new TimeBounds(); - $model->minTime = \DateTime::createFromFormat('U', $xdr->readUnsignedInteger64()); - $model->maxTime = \DateTime::createFromFormat('U', $xdr->readUnsignedInteger64()); - - return $model; - } - - /** - * @return bool - */ - public function isEmpty() - { - return $this->minTime === null && $this->maxTime === null; - } - - /** - * @return \DateTime - */ - public function getMinTime() - { - return $this->minTime; - } - - /** - * @return \DateTime - */ - public function getMaxTime() - { - return $this->maxTime; - } - - /** - * @return int - */ - public function getMinTimestamp() - { - return $this->minTime->format('U'); - } - - /** - * @return int - */ - public function getMaxTimestamp() - { - return $this->maxTime->format('U'); - } +minTime = $minTime; + $this->maxTime = $maxTime; + } + + /** + * @param \DateTime $min + */ + public function setMinTime(\DateTime $min) + { + $this->minTime = clone $min; + } + + /** + * @param \DateTime $max + */ + public function setMaxTime(\DateTime $max) + { + $this->maxTime = clone $max; + } + + public function toXdr() + { + $bytes = ''; + + $bytes .= XdrEncoder::unsignedInteger64($this->getMinTimestamp()); + $bytes .= XdrEncoder::unsignedInteger64($this->getMaxTimestamp()); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return null|TimeBounds + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $model = new TimeBounds(); + $model->minTime = \DateTime::createFromFormat('U', $xdr->readUnsignedInteger64()); + $model->maxTime = \DateTime::createFromFormat('U', $xdr->readUnsignedInteger64()); + + return $model; + } + + /** + * @return bool + */ + public function isEmpty() + { + return $this->minTime === null && $this->maxTime === null; + } + + /** + * @return \DateTime + */ + public function getMinTime() + { + return $this->minTime; + } + + /** + * @return \DateTime + */ + public function getMaxTime() + { + return $this->maxTime; + } + + /** + * @return int + */ + public function getMinTimestamp() + { + return $this->minTime->format('U'); + } + + /** + * @return int + */ + public function getMaxTimestamp() + { + return $this->maxTime->format('U'); + } } \ No newline at end of file diff --git a/src/XdrModel/TransactionEnvelope.php b/src/XdrModel/TransactionEnvelope.php index 540236c..b52b818 100755 --- a/src/XdrModel/TransactionEnvelope.php +++ b/src/XdrModel/TransactionEnvelope.php @@ -1,144 +1,144 @@ -transactionBuilder = $transactionBuilder; - $this->signatures = new VariableArray(); - - return $this; - } - - public function toXdr() - { - $bytes = ''; - - $bytes .= $this->transactionBuilder->toXdr(); - $bytes .= $this->signatures->toXdr(); - - return $bytes; - } - - /** - * @param XdrBuffer $xdr - * @return TransactionEnvelope - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $builder = Transaction::fromXdr($xdr)->toTransactionBuilder(); - - $model = new TransactionEnvelope($builder); - - $numSignatures = $xdr->readUnsignedInteger(); - for ($i=0; $i < $numSignatures; $i++) { - $model->signatures->append(DecoratedSignature::fromXdr($xdr)); - } - - return $model; - } - - /** - * @return string - */ - public function toBase64() - { - return base64_encode($this->toXdr()); - } - - /** - * Returns the hash of the transaction envelope - * - * This hash is what is signed - * - * @return string - */ - public function getHash() - { - return $this->transactionBuilder->hash(); - } - - /** - * Adds signatures using the given keypairs or secret key strings - * - * @param Keypair[]|string[] $keypairsOrsecretKeyStrings - * @return $this - */ - public function sign($keypairsOrsecretKeyStrings, Server $server = null) - { - if (!is_array($keypairsOrsecretKeyStrings)) $keypairsOrsecretKeyStrings = [$keypairsOrsecretKeyStrings]; - - $transactionHash = null; - if ($server) { - $transactionHash = $server->getApiClient()->hash($this->transactionBuilder); - } - else { - $transactionHash = $this->transactionBuilder->hash(); - } - - foreach ($keypairsOrsecretKeyStrings as $keypairOrSecretKeyString) { - if (is_string($keypairOrSecretKeyString)) { - $keypairOrSecretKeyString = Keypair::newFromSeed($keypairOrSecretKeyString); - } - - $decorated = $keypairOrSecretKeyString->signDecorated($transactionHash); - $this->signatures->append($decorated); - } - - return $this; - } - - - public function addRawSignature($signatureBytes, Keypair $keypair) - { - $decorated = new DecoratedSignature($keypair->getHint(), $signatureBytes); - - $this->signatures->append($decorated); - } - - /** - * @param DecoratedSignature $decoratedSignature - */ - public function addDecoratedSignature(DecoratedSignature $decoratedSignature) - { - $this->signatures->append($decoratedSignature); - } - - /** - * @return DecoratedSignature[] - */ - public function getDecoratedSignatures() - { - return $this->signatures->toArray(); - } +transactionBuilder = $transactionBuilder; + $this->signatures = new VariableArray(); + + return $this; + } + + public function toXdr() + { + $bytes = ''; + + $bytes .= $this->transactionBuilder->toXdr(); + $bytes .= $this->signatures->toXdr(); + + return $bytes; + } + + /** + * @param XdrBuffer $xdr + * @return TransactionEnvelope + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $builder = Transaction::fromXdr($xdr)->toTransactionBuilder(); + + $model = new TransactionEnvelope($builder); + + $numSignatures = $xdr->readUnsignedInteger(); + for ($i=0; $i < $numSignatures; $i++) { + $model->signatures->append(DecoratedSignature::fromXdr($xdr)); + } + + return $model; + } + + /** + * @return string + */ + public function toBase64() + { + return base64_encode($this->toXdr()); + } + + /** + * Returns the hash of the transaction envelope + * + * This hash is what is signed + * + * @return string + */ + public function getHash() + { + return $this->transactionBuilder->hash(); + } + + /** + * Adds signatures using the given keypairs or secret key strings + * + * @param Keypair[]|string[] $keypairsOrsecretKeyStrings + * @return $this + */ + public function sign($keypairsOrsecretKeyStrings, Server $server = null) + { + if (!is_array($keypairsOrsecretKeyStrings)) $keypairsOrsecretKeyStrings = [$keypairsOrsecretKeyStrings]; + + $transactionHash = null; + if ($server) { + $transactionHash = $server->getApiClient()->hash($this->transactionBuilder); + } + else { + $transactionHash = $this->transactionBuilder->hash(); + } + + foreach ($keypairsOrsecretKeyStrings as $keypairOrSecretKeyString) { + if (is_string($keypairOrSecretKeyString)) { + $keypairOrSecretKeyString = Keypair::newFromSeed($keypairOrSecretKeyString); + } + + $decorated = $keypairOrSecretKeyString->signDecorated($transactionHash); + $this->signatures->append($decorated); + } + + return $this; + } + + + public function addRawSignature($signatureBytes, Keypair $keypair) + { + $decorated = new DecoratedSignature($keypair->getHint(), $signatureBytes); + + $this->signatures->append($decorated); + } + + /** + * @param DecoratedSignature $decoratedSignature + */ + public function addDecoratedSignature(DecoratedSignature $decoratedSignature) + { + $this->signatures->append($decoratedSignature); + } + + /** + * @return DecoratedSignature[] + */ + public function getDecoratedSignatures() + { + return $this->signatures->toArray(); + } } \ No newline at end of file diff --git a/src/XdrModel/TransactionResult.php b/src/XdrModel/TransactionResult.php index 4654844..0adf2cd 100644 --- a/src/XdrModel/TransactionResult.php +++ b/src/XdrModel/TransactionResult.php @@ -1,131 +1,131 @@ -operationResults = []; - } - - /** - * @param XdrBuffer $xdr - * @return TransactionResult - * @throws \ErrorException - */ - public static function fromXdr(XdrBuffer $xdr) - { - $model = new TransactionResult(); - - // This is the fee in stroops - $model->feeCharged = new StellarAmount(new BigInteger($xdr->readInteger64())); - - $rawCode = $xdr->readInteger(); - $resultCodeMap = [ - '0' => 'success', - '-1' => static::FAILED, - '-2' => static::TOO_EARLY, - '-3' => static::TOO_LATE, - '-4' => static::MISSING_OPERATION, - '-5' => static::BAD_SEQ, - '-6' => static::BAD_AUTH, - '-7' => static::INSUFFICIENT_BALANCE, - '-8' => static::NO_ACCOUNT, - '-9' => static::INSUFFICIENT_FEE, - '-10' => static::BAD_AUTH_EXTRA, - '-11' => static::INTERNAL_ERROR, - ]; - if (!isset($resultCodeMap[$rawCode])) { - throw new \ErrorException(sprintf('Unknown result code %s', $rawCode)); - } - $model->resultCode = $resultCodeMap[$rawCode]; - - $numOperations = $xdr->readInteger(); - for ($i=0; $i < $numOperations; $i++) { - $op = OperationResult::fromXdr($xdr); - $model->operationResults[] = $op; - } - - return $model; - } - - /** - * Returns true if all operations in this transaction succeeded - * @return bool - */ - public function succeeded() - { - return $this->resultCode === static::SUCCESS; - } - - /** - * Returns true if any operation in the transaction failed - * @return bool - */ - public function failed() - { - return !$this->succeeded(); - } - - /** - * @return StellarAmount - */ - public function getFeeCharged() - { - return $this->feeCharged; - } - - /** - * @return string - */ - public function getResultCode() - { - return $this->resultCode; - } - - /** - * @return OperationResult[] - */ - public function getOperationResults() - { - return $this->operationResults; - } +operationResults = []; + } + + /** + * @param XdrBuffer $xdr + * @return TransactionResult + * @throws \ErrorException + */ + public static function fromXdr(XdrBuffer $xdr) + { + $model = new TransactionResult(); + + // This is the fee in stroops + $model->feeCharged = new StellarAmount(new BigInteger($xdr->readInteger64())); + + $rawCode = $xdr->readInteger(); + $resultCodeMap = [ + '0' => 'success', + '-1' => static::FAILED, + '-2' => static::TOO_EARLY, + '-3' => static::TOO_LATE, + '-4' => static::MISSING_OPERATION, + '-5' => static::BAD_SEQ, + '-6' => static::BAD_AUTH, + '-7' => static::INSUFFICIENT_BALANCE, + '-8' => static::NO_ACCOUNT, + '-9' => static::INSUFFICIENT_FEE, + '-10' => static::BAD_AUTH_EXTRA, + '-11' => static::INTERNAL_ERROR, + ]; + if (!isset($resultCodeMap[$rawCode])) { + throw new \ErrorException(sprintf('Unknown result code %s', $rawCode)); + } + $model->resultCode = $resultCodeMap[$rawCode]; + + $numOperations = $xdr->readInteger(); + for ($i=0; $i < $numOperations; $i++) { + $op = OperationResult::fromXdr($xdr); + $model->operationResults[] = $op; + } + + return $model; + } + + /** + * Returns true if all operations in this transaction succeeded + * @return bool + */ + public function succeeded() + { + return $this->resultCode === static::SUCCESS; + } + + /** + * Returns true if any operation in the transaction failed + * @return bool + */ + public function failed() + { + return !$this->succeeded(); + } + + /** + * @return StellarAmount + */ + public function getFeeCharged() + { + return $this->feeCharged; + } + + /** + * @return string + */ + public function getResultCode() + { + return $this->resultCode; + } + + /** + * @return OperationResult[] + */ + public function getOperationResults() + { + return $this->operationResults; + } } \ No newline at end of file diff --git a/src/bin/sync-history.php b/src/bin/sync-history.php index 2181fae..78a56a9 100644 --- a/src/bin/sync-history.php +++ b/src/bin/sync-history.php @@ -1,23 +1,23 @@ -downloadAll(); +downloadAll(); diff --git a/tests/HardwareWallet/AccountMergeOpTest.php b/tests/HardwareWallet/AccountMergeOpTest.php index 19820b6..0e74741 100644 --- a/tests/HardwareWallet/AccountMergeOpTest.php +++ b/tests/HardwareWallet/AccountMergeOpTest.php @@ -1,39 +1,39 @@ -mnemonic); - $destinationKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addMergeOperation($destinationKeypair); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Merge Account: ', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Destination: ' . $destinationKeypair->getPublicKey(), - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + $destinationKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addMergeOperation($destinationKeypair); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Merge Account: ', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Destination: ' . $destinationKeypair->getPublicKey(), + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/AllowTrustOpTest.php b/tests/HardwareWallet/AllowTrustOpTest.php index 71722b9..01d46e9 100644 --- a/tests/HardwareWallet/AllowTrustOpTest.php +++ b/tests/HardwareWallet/AllowTrustOpTest.php @@ -1,127 +1,127 @@ -mnemonic); - $trustedKeypair = Keypair::newFromMnemonic($this->mnemonic, 'trusted keypair'); - $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); - - $asset = Asset::newCustomAsset('JPY', $jpyIssuerKeypair); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->authorizeTrustline($asset, $trustedKeypair); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Allow Trust: authorize', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Asset: ' . $asset->getAssetCode(), - 'Trusted Account: ' . $trustedKeypair->getPublicKey(), - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testRevokeTrust() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $trustedKeypair = Keypair::newFromMnemonic($this->mnemonic, 'trusted keypair'); - $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); - - $asset = Asset::newCustomAsset('JPY', $jpyIssuerKeypair); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->revokeTrustline($asset, $trustedKeypair); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Allow Trust: revoke', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Asset: ' . $asset->getAssetCode(), - 'Trusted Account: ' . $trustedKeypair->getPublicKey(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testAllow7CharAssetTrust() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $trustedKeypair = Keypair::newFromMnemonic($this->mnemonic, 'trusted keypair'); - $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); - - $asset = Asset::newCustomAsset('ABCDEFG', $jpyIssuerKeypair); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->authorizeTrustline($asset, $trustedKeypair); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Allow Trust: authorize 7-character asset', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Asset: ' . $asset->getAssetCode(), - 'Trusted Account: ' . $trustedKeypair->getPublicKey(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testAllow12CharAssetTrust() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $trustedKeypair = Keypair::newFromMnemonic($this->mnemonic, 'trusted keypair'); - $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); - - $asset = Asset::newCustomAsset('ABCDEFGHIJKL', $jpyIssuerKeypair); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->authorizeTrustline($asset, $trustedKeypair); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Allow Trust: authorize 12-character asset', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Asset: ' . $asset->getAssetCode(), - 'Trusted Account: ' . $trustedKeypair->getPublicKey(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + $trustedKeypair = Keypair::newFromMnemonic($this->mnemonic, 'trusted keypair'); + $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); + + $asset = Asset::newCustomAsset('JPY', $jpyIssuerKeypair); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->authorizeTrustline($asset, $trustedKeypair); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Allow Trust: authorize', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Asset: ' . $asset->getAssetCode(), + 'Trusted Account: ' . $trustedKeypair->getPublicKey(), + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testRevokeTrust() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $trustedKeypair = Keypair::newFromMnemonic($this->mnemonic, 'trusted keypair'); + $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); + + $asset = Asset::newCustomAsset('JPY', $jpyIssuerKeypair); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->revokeTrustline($asset, $trustedKeypair); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Allow Trust: revoke', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Asset: ' . $asset->getAssetCode(), + 'Trusted Account: ' . $trustedKeypair->getPublicKey(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testAllow7CharAssetTrust() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $trustedKeypair = Keypair::newFromMnemonic($this->mnemonic, 'trusted keypair'); + $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); + + $asset = Asset::newCustomAsset('ABCDEFG', $jpyIssuerKeypair); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->authorizeTrustline($asset, $trustedKeypair); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Allow Trust: authorize 7-character asset', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Asset: ' . $asset->getAssetCode(), + 'Trusted Account: ' . $trustedKeypair->getPublicKey(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testAllow12CharAssetTrust() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $trustedKeypair = Keypair::newFromMnemonic($this->mnemonic, 'trusted keypair'); + $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); + + $asset = Asset::newCustomAsset('ABCDEFGHIJKL', $jpyIssuerKeypair); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->authorizeTrustline($asset, $trustedKeypair); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Allow Trust: authorize 12-character asset', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Asset: ' . $asset->getAssetCode(), + 'Trusted Account: ' . $trustedKeypair->getPublicKey(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/BumpSequenceOpTest.php b/tests/HardwareWallet/BumpSequenceOpTest.php index 2194f2c..d36d21b 100644 --- a/tests/HardwareWallet/BumpSequenceOpTest.php +++ b/tests/HardwareWallet/BumpSequenceOpTest.php @@ -1,67 +1,67 @@ -mnemonic); - - $bumpTo = new BigInteger(1234567890); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->bumpSequenceTo($bumpTo); - - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Bump Sequence: basic', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Bump To: ' . $bumpTo->toString(), - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testMaxBumpSequence() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $bumpTo = new BigInteger('9223372036854775807'); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->bumpSequenceTo($bumpTo); - - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Bump Sequence: max', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Bump To: ' . $bumpTo->toString(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + + $bumpTo = new BigInteger(1234567890); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->bumpSequenceTo($bumpTo); + + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Bump Sequence: basic', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Bump To: ' . $bumpTo->toString(), + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testMaxBumpSequence() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $bumpTo = new BigInteger('9223372036854775807'); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->bumpSequenceTo($bumpTo); + + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Bump Sequence: max', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Bump To: ' . $bumpTo->toString(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/ChangeTrustOpTest.php b/tests/HardwareWallet/ChangeTrustOpTest.php index 327cfe7..5d4ce82 100644 --- a/tests/HardwareWallet/ChangeTrustOpTest.php +++ b/tests/HardwareWallet/ChangeTrustOpTest.php @@ -1,98 +1,98 @@ -mnemonic); - $asset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd')->getPublicKey()); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addChangeTrustOp($asset, StellarAmount::newMaximum()); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Change Trust: add trustline', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Code: ' . $asset->getAssetCode(), - ' Amount: ' . 'Maximum', - ' Issuer: ' . $asset->getIssuer()->getAccountIdString(), - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testAddTrustline() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $asset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd')->getPublicKey()); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addChangeTrustOp($asset, 1000); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Change Trust: add trustline', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Code: ' . $asset->getAssetCode(), - ' Amount: ' . '1000', - ' Issuer: ' . $asset->getIssuer()->getAccountIdString(), - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testRemoveTrustline() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $asset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd')->getPublicKey()); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addChangeTrustOp($asset, 0); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Change Trust: add trustline', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Code: ' . $asset->getAssetCode(), - ' Amount: ' . '0', - ' Issuer: ' . $asset->getIssuer()->getAccountIdString(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + $asset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd')->getPublicKey()); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addChangeTrustOp($asset, StellarAmount::newMaximum()); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Change Trust: add trustline', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Code: ' . $asset->getAssetCode(), + ' Amount: ' . 'Maximum', + ' Issuer: ' . $asset->getIssuer()->getAccountIdString(), + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testAddTrustline() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $asset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd')->getPublicKey()); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addChangeTrustOp($asset, 1000); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Change Trust: add trustline', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Code: ' . $asset->getAssetCode(), + ' Amount: ' . '1000', + ' Issuer: ' . $asset->getIssuer()->getAccountIdString(), + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testRemoveTrustline() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $asset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd')->getPublicKey()); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addChangeTrustOp($asset, 0); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Change Trust: add trustline', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Code: ' . $asset->getAssetCode(), + ' Amount: ' . '0', + ' Issuer: ' . $asset->getIssuer()->getAccountIdString(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/CreateAccountOpTest.php b/tests/HardwareWallet/CreateAccountOpTest.php index dfb3932..a9b8f1b 100644 --- a/tests/HardwareWallet/CreateAccountOpTest.php +++ b/tests/HardwareWallet/CreateAccountOpTest.php @@ -1,65 +1,65 @@ -mnemonic); - $newKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addCreateAccountOp($newKeypair, 100.0333); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Create Account operation', - ' Source: ' . $sourceKeypair->getPublicKey(), - 'Creating account: ' . $newKeypair->getPublicKey(), - ' Initial balance: ' . 100.0333, - '', - ' B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testCreateAccountWithMaximumValue() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $newKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addCreateAccountOp($newKeypair, new BigInteger('9223372036854775807')); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Create Account operation', - ' Source: ' . $sourceKeypair->getPublicKey(), - 'Creating account: ' . $newKeypair->getPublicKey(), - ' Initial balance: ' . '922337203685.4775807', - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + $newKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addCreateAccountOp($newKeypair, 100.0333); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Create Account operation', + ' Source: ' . $sourceKeypair->getPublicKey(), + 'Creating account: ' . $newKeypair->getPublicKey(), + ' Initial balance: ' . 100.0333, + '', + ' B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testCreateAccountWithMaximumValue() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $newKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addCreateAccountOp($newKeypair, new BigInteger('9223372036854775807')); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Create Account operation', + ' Source: ' . $sourceKeypair->getPublicKey(), + 'Creating account: ' . $newKeypair->getPublicKey(), + ' Initial balance: ' . '922337203685.4775807', + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/CreatePassiveOfferOpTest.php b/tests/HardwareWallet/CreatePassiveOfferOpTest.php index 2fb8f5b..2de969d 100644 --- a/tests/HardwareWallet/CreatePassiveOfferOpTest.php +++ b/tests/HardwareWallet/CreatePassiveOfferOpTest.php @@ -1,81 +1,81 @@ -mnemonic); - $sellingAsset = Asset::newNativeAsset(); - $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); - - $amount = 200; - $price = new Price(674614, 1000000); - - $operation = new CreatePassiveOfferOp($sellingAsset, $buyingAsset, $amount, $price); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - base64_encode($transaction->toXdr()), - 'Passive Offer: new offer', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Selling: ' . $amount . 'XLM', - ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testDeletePassiveOffer() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $sellingAsset = Asset::newNativeAsset(); - $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); - - $amount = 0; - $price = new Price(674614, 1000000); - - $operation = new CreatePassiveOfferOp($sellingAsset, $buyingAsset, $amount, $price); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - base64_encode($transaction->toXdr()), - 'Passive Offer: delete offer', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Selling: ' . $amount . 'XLM', - ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + $sellingAsset = Asset::newNativeAsset(); + $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); + + $amount = 200; + $price = new Price(674614, 1000000); + + $operation = new CreatePassiveOfferOp($sellingAsset, $buyingAsset, $amount, $price); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + base64_encode($transaction->toXdr()), + 'Passive Offer: new offer', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Selling: ' . $amount . 'XLM', + ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testDeletePassiveOffer() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $sellingAsset = Asset::newNativeAsset(); + $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); + + $amount = 0; + $price = new Price(674614, 1000000); + + $operation = new CreatePassiveOfferOp($sellingAsset, $buyingAsset, $amount, $price); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + base64_encode($transaction->toXdr()), + 'Passive Offer: delete offer', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Selling: ' . $amount . 'XLM', + ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/ManageDataOpTest.php b/tests/HardwareWallet/ManageDataOpTest.php index 09102e6..a2e0b01 100644 --- a/tests/HardwareWallet/ManageDataOpTest.php +++ b/tests/HardwareWallet/ManageDataOpTest.php @@ -1,103 +1,103 @@ -mnemonic); - - $dataKey = 'test data'; - $dataValue = 'asdf'; - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->setAccountData($dataKey, $dataValue); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Manage Data: set data', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Key: ' . $dataKey, - ' Value Hash: ' . hash('sha256', $dataValue), - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testSetMaximumLengthDataValue() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $dataKey = join('', [ - 'abcdefghijklmnop', - 'abcdefghijklmnop', - 'abcdefghijklmnop', - 'abcdefghijklmnop', - ]); - - $dataValue = random_bytes(64); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->setAccountData($dataKey, $dataValue); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Manage Data: set data (maximum length key and value)', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Key: ' . $dataKey, - ' Value Hash: ' . hash('sha256', $dataValue), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testClearDataValue() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $dataKey = 'test data'; - $dataValue = null; - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->setAccountData($dataKey, $dataValue); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Manage Data: clear data', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Key: ' . $dataKey, - ' Value Hash: ' . hash('sha256', $dataValue), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + + $dataKey = 'test data'; + $dataValue = 'asdf'; + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->setAccountData($dataKey, $dataValue); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Manage Data: set data', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Key: ' . $dataKey, + ' Value Hash: ' . hash('sha256', $dataValue), + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testSetMaximumLengthDataValue() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $dataKey = join('', [ + 'abcdefghijklmnop', + 'abcdefghijklmnop', + 'abcdefghijklmnop', + 'abcdefghijklmnop', + ]); + + $dataValue = random_bytes(64); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->setAccountData($dataKey, $dataValue); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Manage Data: set data (maximum length key and value)', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Key: ' . $dataKey, + ' Value Hash: ' . hash('sha256', $dataValue), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testClearDataValue() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $dataKey = 'test data'; + $dataValue = null; + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->setAccountData($dataKey, $dataValue); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Manage Data: clear data', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Key: ' . $dataKey, + ' Value Hash: ' . hash('sha256', $dataValue), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/ManageOfferOpTest.php b/tests/HardwareWallet/ManageOfferOpTest.php index 21aaae1..86c7eea 100644 --- a/tests/HardwareWallet/ManageOfferOpTest.php +++ b/tests/HardwareWallet/ManageOfferOpTest.php @@ -1,181 +1,181 @@ -mnemonic); - $sellingAsset = Asset::newNativeAsset(); - $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); - - $amount = 200; - $price = new Price(674614, 1000000); - - $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - base64_encode($transaction->toXdr()), - 'Manage Offer: new offer', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Selling: ' . $amount . 'XLM', - ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testNewMaxAmountOffer() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $sellingAsset = Asset::newNativeAsset(); - $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); - - $amount = 100.99; - $price = new Price(4294967295, 1); - - $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - base64_encode($transaction->toXdr()), - 'Manage Offer: new offer', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Selling: ' . $amount . 'XLM', - ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testNewMinAmountOffer() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $sellingAsset = Asset::newNativeAsset(); - $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); - - $amount = 100.99; - $price = new Price(1, 4294967295); - - $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - base64_encode($transaction->toXdr()), - 'Manage Offer: new offer', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Selling: ' . number_format($amount) . 'XLM', - ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testUpdateOffer() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $sellingAsset = Asset::newNativeAsset(); - $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); - - $amount = 200; - $price = new Price(674614, 1000000); - $offerId = 15528655; - - $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price, $offerId); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - base64_encode($transaction->toXdr()), - 'Manage Offer: update offer', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Offer ID: ' . $offerId, - ' Selling: ' . $amount . 'XLM', - ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testRemoveOffer() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $sellingAsset = Asset::newNativeAsset(); - $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); - - $amount = 0; - $price = new Price(674614, 1000000); - $offerId = 15528655; - - $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price, $offerId); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - base64_encode($transaction->toXdr()), - 'Manage Offer: remove offer', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Offer ID: ' . $offerId, - ' Selling: ' . $amount . 'XLM', - ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + $sellingAsset = Asset::newNativeAsset(); + $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); + + $amount = 200; + $price = new Price(674614, 1000000); + + $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + base64_encode($transaction->toXdr()), + 'Manage Offer: new offer', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Selling: ' . $amount . 'XLM', + ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testNewMaxAmountOffer() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $sellingAsset = Asset::newNativeAsset(); + $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); + + $amount = 100.99; + $price = new Price(4294967295, 1); + + $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + base64_encode($transaction->toXdr()), + 'Manage Offer: new offer', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Selling: ' . $amount . 'XLM', + ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testNewMinAmountOffer() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $sellingAsset = Asset::newNativeAsset(); + $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); + + $amount = 100.99; + $price = new Price(1, 4294967295); + + $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + base64_encode($transaction->toXdr()), + 'Manage Offer: new offer', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Selling: ' . number_format($amount) . 'XLM', + ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testUpdateOffer() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $sellingAsset = Asset::newNativeAsset(); + $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); + + $amount = 200; + $price = new Price(674614, 1000000); + $offerId = 15528655; + + $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price, $offerId); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + base64_encode($transaction->toXdr()), + 'Manage Offer: update offer', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Offer ID: ' . $offerId, + ' Selling: ' . $amount . 'XLM', + ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testRemoveOffer() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $sellingAsset = Asset::newNativeAsset(); + $buyingAsset = Asset::newCustomAsset('USD', Keypair::newFromMnemonic($this->mnemonic, 'usd issuer')); + + $amount = 0; + $price = new Price(674614, 1000000); + $offerId = 15528655; + + $operation = new ManageOfferOp($sellingAsset, $buyingAsset, $amount, $price, $offerId); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + base64_encode($transaction->toXdr()), + 'Manage Offer: remove offer', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Offer ID: ' . $offerId, + ' Selling: ' . $amount . 'XLM', + ' Buying: ' . 'For ' . $price . ' per ' . $buyingAsset->getAssetCode() . ' (' . $buyingAsset->getIssuer()->getAccountIdString() . ')', + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/PathPaymentOpTest.php b/tests/HardwareWallet/PathPaymentOpTest.php index 49d5499..a5f6d3f 100644 --- a/tests/HardwareWallet/PathPaymentOpTest.php +++ b/tests/HardwareWallet/PathPaymentOpTest.php @@ -1,105 +1,105 @@ -mnemonic); - $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); - $maxAmount = 200.9999999; // maximum XLM that the sender is willing to pay - $receivesAmount = 20.0000001; // amount of JPY the receiver gets - - $payWithAsset = Asset::newNativeAsset(); - $receiverGetsAsset = Asset::newCustomAsset('JPY', $jpyIssuerKeypair); - - $operation = new PathPaymentOp( - $payWithAsset, - $maxAmount, - $destKeypair, - $receiverGetsAsset, - $receivesAmount - ); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Path Payment: XLM -> JPY (no paths)', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Max Paid: ' . $maxAmount . ' XLM', - 'Amount Received: ' . sprintf('%s %s (%s)', $receivesAmount, $receiverGetsAsset->getAssetCode(), $receiverGetsAsset->getIssuer()->getAccountIdString()), - ' To: ' . $destKeypair->getPublicKey(), - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testNativeAssetPathPaymentOnePath() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); - $maxAmount = 200.9999999; // maximum XLM that the sender is willing to pay - $receivesAmount = 20.0000001; // amount of JPY the receiver gets - - $payWithAsset = Asset::newNativeAsset(); - $receiverGetsAsset = Asset::newCustomAsset('JPY', $jpyIssuerKeypair); - - $pathAsset1 = Asset::newCustomAsset('PTH1', Keypair::newFromMnemonic($this->mnemonic, 'PTH1')); - - $operation = new PathPaymentOp( - $payWithAsset, - $maxAmount, - $destKeypair, - $receiverGetsAsset, - $receivesAmount - ); - - $operation->addPath($pathAsset1); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Path Payment: XLM -> JPY (one path)', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Max Paid: ' . $maxAmount . ' XLM', - 'Amount Received: ' . sprintf('%s %s (%s)', $receivesAmount, $receiverGetsAsset->getAssetCode(), $receiverGetsAsset->getIssuer()->getAccountIdString()), - ' To: ' . $destKeypair->getPublicKey(), - ' Path 1: ' . sprintf('%s (%s)', $pathAsset1->getAssetCode(), $pathAsset1->getIssuer()->getAccountIdString()), - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); + $maxAmount = 200.9999999; // maximum XLM that the sender is willing to pay + $receivesAmount = 20.0000001; // amount of JPY the receiver gets + + $payWithAsset = Asset::newNativeAsset(); + $receiverGetsAsset = Asset::newCustomAsset('JPY', $jpyIssuerKeypair); + + $operation = new PathPaymentOp( + $payWithAsset, + $maxAmount, + $destKeypair, + $receiverGetsAsset, + $receivesAmount + ); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Path Payment: XLM -> JPY (no paths)', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Max Paid: ' . $maxAmount . ' XLM', + 'Amount Received: ' . sprintf('%s %s (%s)', $receivesAmount, $receiverGetsAsset->getAssetCode(), $receiverGetsAsset->getIssuer()->getAccountIdString()), + ' To: ' . $destKeypair->getPublicKey(), + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testNativeAssetPathPaymentOnePath() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + $jpyIssuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'jpy issuer'); + $maxAmount = 200.9999999; // maximum XLM that the sender is willing to pay + $receivesAmount = 20.0000001; // amount of JPY the receiver gets + + $payWithAsset = Asset::newNativeAsset(); + $receiverGetsAsset = Asset::newCustomAsset('JPY', $jpyIssuerKeypair); + + $pathAsset1 = Asset::newCustomAsset('PTH1', Keypair::newFromMnemonic($this->mnemonic, 'PTH1')); + + $operation = new PathPaymentOp( + $payWithAsset, + $maxAmount, + $destKeypair, + $receiverGetsAsset, + $receivesAmount + ); + + $operation->addPath($pathAsset1); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Path Payment: XLM -> JPY (one path)', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Max Paid: ' . $maxAmount . ' XLM', + 'Amount Received: ' . sprintf('%s %s (%s)', $receivesAmount, $receiverGetsAsset->getAssetCode(), $receiverGetsAsset->getIssuer()->getAccountIdString()), + ' To: ' . $destKeypair->getPublicKey(), + ' Path 1: ' . sprintf('%s (%s)', $pathAsset1->getAssetCode(), $pathAsset1->getIssuer()->getAccountIdString()), + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/PaymentOpTest.php b/tests/HardwareWallet/PaymentOpTest.php index 14fea44..ea010bf 100644 --- a/tests/HardwareWallet/PaymentOpTest.php +++ b/tests/HardwareWallet/PaymentOpTest.php @@ -1,168 +1,168 @@ -mnemonic); - $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - $amount = 50.0111; - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addLumenPayment($destKeypair, $amount); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Payment: native asset', - 'Source: ' . $sourceKeypair->getPublicKey(), - ' Pay: ' . $amount . ' XLM', - ' To: ' . $destKeypair->getPublicKey(), - '', - ' B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testCustomAsset1Payment() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - $amount = 50.0111; - - $issuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'issuer'); - $asset = Asset::newCustomAsset('X', $issuerKeypair->getPublicKey()); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addCustomAssetPaymentOp($asset, $amount, $destKeypair); - - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Payment: custom asset (1-char)', - 'Source: ' . $sourceKeypair->getPublicKey(), - ' Pay: ' . sprintf('%s %s (%s)', $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString()), - ' To: ' . $destKeypair->getPublicKey(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testCustomAsset4Payment() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - $amount = 50.0111; - - $issuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'issuer'); - $asset = Asset::newCustomAsset('TEST', $issuerKeypair->getPublicKey()); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addCustomAssetPaymentOp($asset, $amount, $destKeypair); - - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Payment: custom asset (4-char)', - 'Source: ' . $sourceKeypair->getPublicKey(), - ' Pay: ' . sprintf('%s %s (%s)', $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString()), - ' To: ' . $destKeypair->getPublicKey(), - '', - ' B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testCustomAsset7Payment() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - $amount = 50.0111; - - $issuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'issuer'); - $asset = Asset::newCustomAsset('SEVENXX', $issuerKeypair->getPublicKey()); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addCustomAssetPaymentOp($asset, $amount, $destKeypair); - - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Payment: custom asset (7-char)', - 'Source: ' . $sourceKeypair->getPublicKey(), - ' Pay: ' . sprintf('%s %s (%s)', $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString()), - ' To: ' . $destKeypair->getPublicKey(), - '', - ' B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testCustomAsset12Payment() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); - $amount = 50.0111; - - $issuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'issuer'); - $asset = Asset::newCustomAsset('ABCDEFGHIJKL', $issuerKeypair->getPublicKey()); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addCustomAssetPaymentOp($asset, $amount, $destKeypair); - - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Payment: custom asset (12-char)', - 'Source: ' . $sourceKeypair->getPublicKey(), - ' Pay: ' . sprintf('%s %s (%s)', $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString()), - ' To: ' . $destKeypair->getPublicKey(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + $amount = 50.0111; + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addLumenPayment($destKeypair, $amount); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Payment: native asset', + 'Source: ' . $sourceKeypair->getPublicKey(), + ' Pay: ' . $amount . ' XLM', + ' To: ' . $destKeypair->getPublicKey(), + '', + ' B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testCustomAsset1Payment() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + $amount = 50.0111; + + $issuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'issuer'); + $asset = Asset::newCustomAsset('X', $issuerKeypair->getPublicKey()); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addCustomAssetPaymentOp($asset, $amount, $destKeypair); + + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Payment: custom asset (1-char)', + 'Source: ' . $sourceKeypair->getPublicKey(), + ' Pay: ' . sprintf('%s %s (%s)', $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString()), + ' To: ' . $destKeypair->getPublicKey(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testCustomAsset4Payment() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + $amount = 50.0111; + + $issuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'issuer'); + $asset = Asset::newCustomAsset('TEST', $issuerKeypair->getPublicKey()); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addCustomAssetPaymentOp($asset, $amount, $destKeypair); + + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Payment: custom asset (4-char)', + 'Source: ' . $sourceKeypair->getPublicKey(), + ' Pay: ' . sprintf('%s %s (%s)', $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString()), + ' To: ' . $destKeypair->getPublicKey(), + '', + ' B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testCustomAsset7Payment() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + $amount = 50.0111; + + $issuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'issuer'); + $asset = Asset::newCustomAsset('SEVENXX', $issuerKeypair->getPublicKey()); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addCustomAssetPaymentOp($asset, $amount, $destKeypair); + + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Payment: custom asset (7-char)', + 'Source: ' . $sourceKeypair->getPublicKey(), + ' Pay: ' . sprintf('%s %s (%s)', $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString()), + ' To: ' . $destKeypair->getPublicKey(), + '', + ' B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testCustomAsset12Payment() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $destKeypair = Keypair::newFromMnemonic($this->mnemonic, 'destination'); + $amount = 50.0111; + + $issuerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'issuer'); + $asset = Asset::newCustomAsset('ABCDEFGHIJKL', $issuerKeypair->getPublicKey()); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addCustomAssetPaymentOp($asset, $amount, $destKeypair); + + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Payment: custom asset (12-char)', + 'Source: ' . $sourceKeypair->getPublicKey(), + ' Pay: ' . sprintf('%s %s (%s)', $amount, $asset->getAssetCode(), $asset->getIssuer()->getAccountIdString()), + ' To: ' . $destKeypair->getPublicKey(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/HardwareWallet/SetOptionsOpTest.php b/tests/HardwareWallet/SetOptionsOpTest.php index 144f65c..a3028a3 100644 --- a/tests/HardwareWallet/SetOptionsOpTest.php +++ b/tests/HardwareWallet/SetOptionsOpTest.php @@ -1,386 +1,386 @@ -mnemonic); - $inflationDestination = Keypair::newFromMnemonic($this->mnemonic, 'inflation destination'); - - $operation = new SetOptionsOp(); - $operation->setInflationDestination($inflationDestination); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: inflation destination', - ' Source: ' . $sourceKeypair->getPublicKey(), - 'Inf. Destination: ' . $inflationDestination->getPublicKey(), - '', - 'B64 Transaction: ' . base64_encode($transaction->toXdr()), - ' Signature: ' . $knownSignature->getWithoutHintBase64(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testClearOneFlag() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $operation = new SetOptionsOp(); - $operation->setAuthRevocable(false); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: clear one flag', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Flags Cleared: ' . 'AUTH_REVOCABLE' - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testClearAllFlags() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $operation = new SetOptionsOp(); - $operation->setAuthRevocable(false); - $operation->setAuthRequired(false); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: clear all flags', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Flags Cleared: ' . 'AUTH_REVOCABLE, AUTH_REQUIRED' - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testSetOneFlag() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $operation = new SetOptionsOp(); - $operation->setAuthRevocable(true); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Set Option: set one flag', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Flags Set: ' . 'AUTH_REVOCABLE' - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testSetAllFlags() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $operation = new SetOptionsOp(); - $operation->setAuthRevocable(true); - $operation->setAuthRequired(true); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - 'Set Option: set all flags', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Flags Set: ' . 'AUTH_REVOCABLE, AUTH_REQUIRED' - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testSetMasterWeight() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $operation = new SetOptionsOp(); - $operation->setMasterWeight(128); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: master weight', - ' Source: ' . $sourceKeypair->getPublicKey(), - 'Master Weight: ' . $operation->getMasterWeight(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testSetAllThresholds() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $operation = new SetOptionsOp(); - $operation->setMasterWeight(255); - $operation->setLowThreshold(128); - $operation->setMediumThreshold(16); - $operation->setHighThreshold(0); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: all thresholds', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Master: ' . $operation->getMasterWeight(), - ' Low: ' . $operation->getLowThreshold(), - ' Medium: ' . $operation->getMediumThreshold(), - ' High: ' . $operation->getHighThreshold(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testSetHomeDomain() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $operation = new SetOptionsOp(); - $operation->setHomeDomain('example.com'); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: home domain', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Domain: ' . $operation->getHomeDomain(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testSetMaxLengthHomeDomain() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $operation = new SetOptionsOp(); - $operation->setHomeDomain('abcdefghijklmnopqrstuvwxyzabcdef'); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: home domain (max length)', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Domain: ' . $operation->getHomeDomain(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testAddAccountSigner() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $signerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'new signer'); - - $signerKey = SignerKey::fromKeypair($signerKeypair); - $signer = new Signer($signerKey, 100); - - $operation = new SetOptionsOp(); - $operation->updateSigner($signer); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: add signer (account)', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Signer: ' . $signerKeypair->getPublicKey(), - ' Weight: ' . $signer->getWeight(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testRemoveAccountSigner() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - $signerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'new signer'); - - $signerKey = SignerKey::fromKeypair($signerKeypair); - $signer = new Signer($signerKey, 0); - - $operation = new SetOptionsOp(); - $operation->updateSigner($signer); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: add signer (account)', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Signer: ' . $signerKeypair->getPublicKey(), - ' Weight: ' . $signer->getWeight(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testAddPreAuthHashSigner() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $hashedValue = 'asdf'; - $signerKey = SignerKey::fromPreauthorizedHash(hash('sha256', $hashedValue, true)); - $signer = new Signer($signerKey, 1); - - $operation = new SetOptionsOp(); - $operation->updateSigner($signer); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: add signer (account)', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Signer: ' . hash('sha256', $hashedValue), - ' Weight: ' . $signer->getWeight(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } - - /** - * @group requires-hardwarewallet - */ - public function testAddHashXSigner() - { - $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); - - $hashedValue = 'asdf'; - $signerKey = SignerKey::fromHashX($hashedValue); - $signer = new Signer($signerKey, 1); - - $operation = new SetOptionsOp(); - $operation->updateSigner($signer); - - $transaction = $this->horizonServer - ->buildTransaction($sourceKeypair) - ->setSequenceNumber(new BigInteger(4294967296)) - ->addOperation($operation); - $knownSignature = $transaction->signWith($this->privateKeySigner); - - $this->manualVerificationOutput(join(PHP_EOL, [ - ' Set Option: add signer (account)', - ' Source: ' . $sourceKeypair->getPublicKey(), - ' Signer: ' . hash('sha256', $hashedValue), - ' Weight: ' . $signer->getWeight(), - ])); - $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); - - $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); - } +mnemonic); + $inflationDestination = Keypair::newFromMnemonic($this->mnemonic, 'inflation destination'); + + $operation = new SetOptionsOp(); + $operation->setInflationDestination($inflationDestination); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: inflation destination', + ' Source: ' . $sourceKeypair->getPublicKey(), + 'Inf. Destination: ' . $inflationDestination->getPublicKey(), + '', + 'B64 Transaction: ' . base64_encode($transaction->toXdr()), + ' Signature: ' . $knownSignature->getWithoutHintBase64(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testClearOneFlag() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $operation = new SetOptionsOp(); + $operation->setAuthRevocable(false); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: clear one flag', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Flags Cleared: ' . 'AUTH_REVOCABLE' + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testClearAllFlags() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $operation = new SetOptionsOp(); + $operation->setAuthRevocable(false); + $operation->setAuthRequired(false); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: clear all flags', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Flags Cleared: ' . 'AUTH_REVOCABLE, AUTH_REQUIRED' + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testSetOneFlag() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $operation = new SetOptionsOp(); + $operation->setAuthRevocable(true); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Set Option: set one flag', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Flags Set: ' . 'AUTH_REVOCABLE' + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testSetAllFlags() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $operation = new SetOptionsOp(); + $operation->setAuthRevocable(true); + $operation->setAuthRequired(true); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + 'Set Option: set all flags', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Flags Set: ' . 'AUTH_REVOCABLE, AUTH_REQUIRED' + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testSetMasterWeight() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $operation = new SetOptionsOp(); + $operation->setMasterWeight(128); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: master weight', + ' Source: ' . $sourceKeypair->getPublicKey(), + 'Master Weight: ' . $operation->getMasterWeight(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testSetAllThresholds() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $operation = new SetOptionsOp(); + $operation->setMasterWeight(255); + $operation->setLowThreshold(128); + $operation->setMediumThreshold(16); + $operation->setHighThreshold(0); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: all thresholds', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Master: ' . $operation->getMasterWeight(), + ' Low: ' . $operation->getLowThreshold(), + ' Medium: ' . $operation->getMediumThreshold(), + ' High: ' . $operation->getHighThreshold(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testSetHomeDomain() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $operation = new SetOptionsOp(); + $operation->setHomeDomain('example.com'); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: home domain', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Domain: ' . $operation->getHomeDomain(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testSetMaxLengthHomeDomain() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $operation = new SetOptionsOp(); + $operation->setHomeDomain('abcdefghijklmnopqrstuvwxyzabcdef'); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: home domain (max length)', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Domain: ' . $operation->getHomeDomain(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testAddAccountSigner() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $signerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'new signer'); + + $signerKey = SignerKey::fromKeypair($signerKeypair); + $signer = new Signer($signerKey, 100); + + $operation = new SetOptionsOp(); + $operation->updateSigner($signer); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: add signer (account)', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Signer: ' . $signerKeypair->getPublicKey(), + ' Weight: ' . $signer->getWeight(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testRemoveAccountSigner() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + $signerKeypair = Keypair::newFromMnemonic($this->mnemonic, 'new signer'); + + $signerKey = SignerKey::fromKeypair($signerKeypair); + $signer = new Signer($signerKey, 0); + + $operation = new SetOptionsOp(); + $operation->updateSigner($signer); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: add signer (account)', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Signer: ' . $signerKeypair->getPublicKey(), + ' Weight: ' . $signer->getWeight(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testAddPreAuthHashSigner() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $hashedValue = 'asdf'; + $signerKey = SignerKey::fromPreauthorizedHash(hash('sha256', $hashedValue, true)); + $signer = new Signer($signerKey, 1); + + $operation = new SetOptionsOp(); + $operation->updateSigner($signer); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: add signer (account)', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Signer: ' . hash('sha256', $hashedValue), + ' Weight: ' . $signer->getWeight(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } + + /** + * @group requires-hardwarewallet + */ + public function testAddHashXSigner() + { + $sourceKeypair = Keypair::newFromMnemonic($this->mnemonic); + + $hashedValue = 'asdf'; + $signerKey = SignerKey::fromHashX($hashedValue); + $signer = new Signer($signerKey, 1); + + $operation = new SetOptionsOp(); + $operation->updateSigner($signer); + + $transaction = $this->horizonServer + ->buildTransaction($sourceKeypair) + ->setSequenceNumber(new BigInteger(4294967296)) + ->addOperation($operation); + $knownSignature = $transaction->signWith($this->privateKeySigner); + + $this->manualVerificationOutput(join(PHP_EOL, [ + ' Set Option: add signer (account)', + ' Source: ' . $sourceKeypair->getPublicKey(), + ' Signer: ' . hash('sha256', $hashedValue), + ' Weight: ' . $signer->getWeight(), + ])); + $hardwareSignature = $transaction->signWith($this->horizonServer->getSigningProvider()); + + $this->assertEquals($knownSignature->toBase64(), $hardwareSignature->toBase64()); + } } \ No newline at end of file diff --git a/tests/Unit/Derivation/Bip39/Bip39Test.php b/tests/Unit/Derivation/Bip39/Bip39Test.php index 4603e28..58fa363 100644 --- a/tests/Unit/Derivation/Bip39/Bip39Test.php +++ b/tests/Unit/Derivation/Bip39/Bip39Test.php @@ -1,72 +1,72 @@ -assertEquals( - bin2hex($bip39->mnemonicToEntropy($mnemonic)), - $entropyHex - ); - - $this->assertEquals( - bin2hex($bip39->mnemonicToSeedBytesWithErrorChecking($mnemonic, 'TREZOR')), - $seedHex - ); - } - public function mnemonicToEntropyProvider() - { - return [ - [ - 'mnemonic' => 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', - 'entropyHex' => '00000000000000000000000000000000', - 'seedHex' => 'c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04', - ], - [ - 'mnemonic' => 'legal winner thank year wave sausage worth useful legal winner thank yellow', - 'entropyHex' => '7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f', - 'seedHex' => '2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607', - ], - [ - 'mnemonic' => 'legal winner thank year wave sausage worth useful legal winner thank yellow', - 'entropyHex' => '7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f', - 'seedHex' => '2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607', - ], - [ - 'mnemonic' => 'letter advice cage absurd amount doctor acoustic avoid letter advice cage above', - 'entropyHex' => '80808080808080808080808080808080', - 'seedHex' => 'd71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8', - ], - - [ - 'mnemonic' => 'all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform', - 'entropyHex' => '066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad', - 'seedHex' => '26e975ec644423f4a4c4f4215ef09b4bd7ef924e85d1d17c4cf3f136c2863cf6df0a475045652c57eb5fb41513ca2a2d67722b77e954b4b3fc11f7590449191d', - ], - ]; - } +assertEquals( + bin2hex($bip39->mnemonicToEntropy($mnemonic)), + $entropyHex + ); + + $this->assertEquals( + bin2hex($bip39->mnemonicToSeedBytesWithErrorChecking($mnemonic, 'TREZOR')), + $seedHex + ); + } + public function mnemonicToEntropyProvider() + { + return [ + [ + 'mnemonic' => 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', + 'entropyHex' => '00000000000000000000000000000000', + 'seedHex' => 'c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04', + ], + [ + 'mnemonic' => 'legal winner thank year wave sausage worth useful legal winner thank yellow', + 'entropyHex' => '7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f', + 'seedHex' => '2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607', + ], + [ + 'mnemonic' => 'legal winner thank year wave sausage worth useful legal winner thank yellow', + 'entropyHex' => '7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f', + 'seedHex' => '2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607', + ], + [ + 'mnemonic' => 'letter advice cage absurd amount doctor acoustic avoid letter advice cage above', + 'entropyHex' => '80808080808080808080808080808080', + 'seedHex' => 'd71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8', + ], + + [ + 'mnemonic' => 'all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform', + 'entropyHex' => '066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad', + 'seedHex' => '26e975ec644423f4a4c4f4215ef09b4bd7ef924e85d1d17c4cf3f136c2863cf6df0a475045652c57eb5fb41513ca2a2d67722b77e954b4b3fc11f7590449191d', + ], + ]; + } } \ No newline at end of file diff --git a/tests/Unit/Derivation/HdNodeTest.php b/tests/Unit/Derivation/HdNodeTest.php index b7d86b8..4c18e23 100644 --- a/tests/Unit/Derivation/HdNodeTest.php +++ b/tests/Unit/Derivation/HdNodeTest.php @@ -1,70 +1,70 @@ -assertEquals( - '2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7', - bin2hex($node->getPrivateKeyBytes())); - - $this->assertEquals( - '90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb', - bin2hex($node->getChainCodeBytes())); - } - - public function testMasterNodeDerives() - { - $entropy = hex2bin('000102030405060708090a0b0c0d0e0f'); - $node = HdNode::newMasterNode($entropy); - - // m/0' - $derived = $node->derive(0); - $this->assertEquals( - '68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3', - bin2hex($derived->getPrivateKeyBytes())); - $this->assertEquals( - '8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69', - bin2hex($derived->getChainCodeBytes())); - - // m/0'/1' - $derived = $derived->derive(1); - $this->assertEquals( - 'b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2', - bin2hex($derived->getPrivateKeyBytes())); - $this->assertEquals( - 'a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14', - bin2hex($derived->getChainCodeBytes()));; - } - - public function testMasterNodeDerivesPath() - { - $entropy = hex2bin('000102030405060708090a0b0c0d0e0f'); - $node = HdNode::newMasterNode($entropy); - - $derived = $node->derivePath("m/0'/1'/2'"); - $this->assertEquals( - '92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9', - bin2hex($derived->getPrivateKeyBytes())); - $this->assertEquals( - '2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c', - bin2hex($derived->getChainCodeBytes())); - } - - private function debugNode(HdNode $node) - { - print "\n"; - print "private : " . bin2hex($node->getPrivateKeyBytes()) . "\n"; - print "chaincode: " . bin2hex($node->getChainCodeBytes()) . "\n"; - } +assertEquals( + '2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7', + bin2hex($node->getPrivateKeyBytes())); + + $this->assertEquals( + '90046a93de5380a72b5e45010748567d5ea02bbf6522f979e05c0d8d8ca9fffb', + bin2hex($node->getChainCodeBytes())); + } + + public function testMasterNodeDerives() + { + $entropy = hex2bin('000102030405060708090a0b0c0d0e0f'); + $node = HdNode::newMasterNode($entropy); + + // m/0' + $derived = $node->derive(0); + $this->assertEquals( + '68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3', + bin2hex($derived->getPrivateKeyBytes())); + $this->assertEquals( + '8b59aa11380b624e81507a27fedda59fea6d0b779a778918a2fd3590e16e9c69', + bin2hex($derived->getChainCodeBytes())); + + // m/0'/1' + $derived = $derived->derive(1); + $this->assertEquals( + 'b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2', + bin2hex($derived->getPrivateKeyBytes())); + $this->assertEquals( + 'a320425f77d1b5c2505a6b1b27382b37368ee640e3557c315416801243552f14', + bin2hex($derived->getChainCodeBytes()));; + } + + public function testMasterNodeDerivesPath() + { + $entropy = hex2bin('000102030405060708090a0b0c0d0e0f'); + $node = HdNode::newMasterNode($entropy); + + $derived = $node->derivePath("m/0'/1'/2'"); + $this->assertEquals( + '92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9', + bin2hex($derived->getPrivateKeyBytes())); + $this->assertEquals( + '2e69929e00b5ab250f49c3fb1c12f252de4fed2c1db88387094a0f8c4c9ccd6c', + bin2hex($derived->getChainCodeBytes())); + } + + private function debugNode(HdNode $node) + { + print "\n"; + print "private : " . bin2hex($node->getPrivateKeyBytes()) . "\n"; + print "chaincode: " . bin2hex($node->getChainCodeBytes()) . "\n"; + } } \ No newline at end of file diff --git a/tests/Unit/Derivation/Sep0005Test.php b/tests/Unit/Derivation/Sep0005Test.php index 9c0a73c..6d4695c 100644 --- a/tests/Unit/Derivation/Sep0005Test.php +++ b/tests/Unit/Derivation/Sep0005Test.php @@ -1,163 +1,163 @@ -assertEquals($publicKey, $keypair->getPublicKey()); - $this->assertEquals($privateKey, $keypair->getSecret()); - } - public function newKeypairFromMnemonicProvider() - { - return [ - [ - 'cable spray genius state float twenty onion head street palace net private method loan turn phrase state blanket interest dry amazing dress blast tube', - 'p4ssphr4se', - 'GDAHPZ2NSYIIHZXM56Y36SBVTV5QKFIZGYMMBHOU53ETUSWTP62B63EQ', - 'SAFWTGXVS7ELMNCXELFWCFZOPMHUZ5LXNBGUVRCY3FHLFPXK4QPXYP2X', - ], - ]; - } - - /** - * @dataProvider sep0005Provider - */ - public function testSep0005($mnemonic, $passphrase, $masterSeedHex, $addressNodeKeyHex, $keys) - { - print "\n"; - - $bip39 = new Bip39(); - $seedBytes = $bip39->mnemonicToSeedBytesWithErrorChecking($mnemonic, $passphrase); - $this->assertEquals(bin2hex($seedBytes), $masterSeedHex); - - $masterNode = HdNode::newMasterNode($seedBytes); - $addressNode = $masterNode->derivePath("m/44'/148'"); - $this->assertEquals($addressNodeKeyHex, bin2hex($addressNode->getPrivateKeyBytes())); - - $keyIdx = 0; - foreach ($keys as $publicString => $privateString) { - $accountNode = $addressNode->derive($keyIdx); - $keypair = Keypair::newFromRawSeed($accountNode->getPrivateKeyBytes()); - - $this->assertEquals($publicString, $keypair->getPublicKey()); - $this->assertEquals($privateString, $keypair->getSecret()); - - $keyIdx++; - } - } - public function sep0005Provider() - { - return [ - // From entropy bytes 00000000000000000000000000000000 - [ - 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', - '', - '5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4', - '03df7921b4f789040e361d07d5e4eddad277c376350d7b5d585400a0ef18f2f5', - [ - 'GB3JDWCQJCWMJ3IILWIGDTQJJC5567PGVEVXSCVPEQOTDN64VJBDQBYX' => 'SBUV3MRWKNS6AYKZ6E6MOUVF2OYMON3MIUASWL3JLY5E3ISDJFELYBRZ', - 'GDVSYYTUAJ3ACHTPQNSTQBDQ4LDHQCMNY4FCEQH5TJUMSSLWQSTG42MV' => 'SCHDCVCWGAKGIMTORV6K5DYYV3BY4WG3RA4M6MCBGJLHUCWU2MC6DL66', - 'GBFPWBTN4AXHPWPTQVQBP4KRZ2YVYYOGRMV2PEYL2OBPPJDP7LECEVHR' => 'SAPLVTLUXSDLFRDGCCFLPDZMTCEVMP3ZXTM74EBJCVKZKM34LGQPF7K3', - 'GCCCOWAKYVFY5M6SYHOW33TSNC7Z5IBRUEU2XQVVT34CIZU7CXZ4OQ4O' => 'SDQYXOP2EAUZP4YOEQ5BUJIQ3RDSP5XV4ZFI6C5Y3QCD5Y63LWPXT7PW', - 'GCQ3J35MKPKJX7JDXRHC5YTXTULFMCBMZ5IC63EDR66QA3LO7264ZL7Q' => 'SCT7DUHYZD6DRCETT6M73GWKFJI4D56P3SNWNWNJ7ANLJZS6XIFYYXSB', - 'GDTA7622ZA5PW7F7JL7NOEFGW62M7GW2GY764EQC2TUJ42YJQE2A3QUL' => 'SDTWG5AFDI6GRQNLPWOC7IYS7AKOGMI2GX4OXTBTZHHYPMNZ2PX4ONWU', - 'GD7A7EACTPTBCYCURD43IEZXGIBCEXNBHN3OFWV2FOX67XKUIGRCTBNU' => 'SDJMWY4KFRS4PTA5WBFVCPS2GKYLXOMCLQSBNEIBG7KRGHNQOM25KMCP', - 'GAF4AGPVLQXFKEWQV3DZU5YEFU6YP7XJHAEEQH4G3R664MSF77FLLRK3' => 'SDOJH5JRCNGT57QTPTJEQGBEBZJPXE7XUDYDB24VTOPP7PH3ALKHAHFG', - 'GABTYCZJMCP55SS6I46SR76IHETZDLG4L37MLZRZKQDGBLS5RMP65TSX' => 'SC6N6GYQ2VA4T7CUP2BWGBRT2P6L2HQSZIUNQRHNDLISF6ND7TW4P4ER', - 'GAKFARYSPI33KUJE7HYLT47DCX2PFWJ77W3LZMRBPSGPGYPMSDBE7W7X' => 'SALJ5LPBTXCFML2CQ7ORP7WJNJOZSVBVRQAAODMVHMUF4P4XXFZB7MKY', - ] - ], - [ - 'illness spike retreat truth genius clock brain pass fit cave bargain toe', - '', - 'e4a5a632e70943ae7f07659df1332160937fad82587216a4c64315a0fb39497ee4a01f76ddab4cba68147977f3a147b6ad584c41808e8238a07f6cc4b582f186', - 'e0eec84fe165cd427cb7bc9b6cfdef0555aa1cb6f9043ff1fe986c3c8ddd22e3', - [ - 'GDRXE2BQUC3AZNPVFSCEZ76NJ3WWL25FYFK6RGZGIEKWE4SOOHSUJUJ6' => 'SBGWSG6BTNCKCOB3DIFBGCVMUPQFYPA2G4O34RMTB343OYPXU5DJDVMN', - 'GBAW5XGWORWVFE2XTJYDTLDHXTY2Q2MO73HYCGB3XMFMQ562Q2W2GJQX' => 'SCEPFFWGAG5P2VX5DHIYK3XEMZYLTYWIPWYEKXFHSK25RVMIUNJ7CTIS', - 'GAY5PRAHJ2HIYBYCLZXTHID6SPVELOOYH2LBPH3LD4RUMXUW3DOYTLXW' => 'SDAILLEZCSA67DUEP3XUPZJ7NYG7KGVRM46XA7K5QWWUIGADUZCZWTJP', - 'GAOD5NRAEORFE34G5D4EOSKIJB6V4Z2FGPBCJNQI6MNICVITE6CSYIAE' => 'SBMWLNV75BPI2VB4G27RWOMABVRTSSF7352CCYGVELZDSHCXWCYFKXIX', - 'GBCUXLFLSL2JE3NWLHAWXQZN6SQC6577YMAU3M3BEMWKYPFWXBSRCWV4' => 'SCPCY3CEHMOP2TADSV2ERNNZBNHBGP4V32VGOORIEV6QJLXD5NMCJUXI', - 'GBRQY5JFN5UBG5PGOSUOL4M6D7VRMAYU6WW2ZWXBMCKB7GPT3YCBU2XZ' => 'SCK27SFHI3WUDOEMJREV7ZJQG34SCBR6YWCE6OLEXUS2VVYTSNGCRS6X', - 'GBY27SJVFEWR3DUACNBSMJB6T4ZPR4C7ZXSTHT6GMZUDL23LAM5S2PQX' => 'SDJ4WDPOQAJYR3YIAJOJP3E6E4BMRB7VZ4QAEGCP7EYVDW6NQD3LRJMZ', - 'GAY7T23Z34DWLSTEAUKVBPHHBUE4E3EMZBAQSLV6ZHS764U3TKUSNJOF' => 'SA3HXJUCE2N27TBIZ5JRBLEBF3TLPQEBINP47E6BTMIWW2RJ5UKR2B3L', - 'GDJTCF62UUYSAFAVIXHPRBR4AUZV6NYJR75INVDXLLRZLZQ62S44443R' => 'SCD5OSHUUC75MSJG44BAT3HFZL2HZMMQ5M4GPDL7KA6HJHV3FLMUJAME', - 'GBTVYYDIYWGUQUTKX6ZMLGSZGMTESJYJKJWAATGZGITA25ZB6T5REF44' => 'SCJGVMJ66WAUHQHNLMWDFGY2E72QKSI3XGSBYV6BANDFUFE7VY4XNXXR', - ] - ], - [ - 'resource asthma orphan phone ice canvas fire useful arch jewel impose vague theory cushion top', - '', - '7b36d4e725b48695c3ffd2b4b317d5552cb157c1a26c46d36a05317f0d3053eb8b3b6496ba39ebd9312d10e3f9937b47a6790541e7c577da027a564862e92811', - '2e5d4e6b54a4b96c5e887c9ec92f619a3c134d8b1059dcef15c1a9b228ae3751', - [ - 'GAVXVW5MCK7Q66RIBWZZKZEDQTRXWCZUP4DIIFXCCENGW2P6W4OA34RH' => 'SAKS7I2PNDBE5SJSUSU2XLJ7K5XJ3V3K4UDFAHMSBQYPOKE247VHAGDB', - 'GDFCYVCICATX5YPJUDS22KM2GW5QU2KKSPPPT2IC5AQIU6TP3BZSLR5K' => 'SAZ2H5GLAVWCUWNPQMB6I3OHRI63T2ACUUAWSH7NAGYYPXGIOPLPW3Q4', - 'GAUA3XK3SGEQFNCBM423WIM5WCZ4CR4ZDPDFCYSFLCTODGGGJMPOHAAE' => 'SDVSSLPL76I33DKAI4LFTOAKCHJNCXUERGPCMVFT655Z4GRLWM6ZZTSC', - 'GAH3S77QXTAPZ77REY6LGFIJ2XWVXFOKXHCFLA6HQTL3POLVZJDHHUDM' => 'SCH56YSGOBYVBC6DO3ZI2PY62GBVXT4SEJSXJOBQYGC2GCEZSB5PEVBZ', - 'GCSCZVGV2Y3EQ2RATJ7TE6PVWTW5OH5SMG754AF6W6YM3KJF7RMNPB4Y' => 'SBWBM73VUNBGBMFD4E2BA7Q756AKVEAAVTQH34RYEUFD6X64VYL5KXQ2', - 'GDKWYAJE3W6PWCXDZNMFNFQSPTF6BUDANE6OVRYMJKBYNGL62VKKCNCC' => 'SAVS4CDQZI6PSA5DPCC42S5WLKYIPKXPCJSFYY4N3VDK25T2XX2BTGVX', - 'GCDTVB4XDLNX22HI5GUWHBXJFBCPB6JNU6ZON7E57FA3LFURS74CWDJH' => 'SDFC7WZT3GDQVQUQMXN7TC7UWDW5E3GSMFPHUT2TSTQ7RKWTRA4PLBAL', - 'GBTDPL5S4IOUQHDLCZ7I2UXJ2TEHO6DYIQ3F2P5OOP3IS7JSJI4UMHQJ' => 'SA6UO2FIYC6AS2MSDECLR6F7NKCJTG67F7R4LV2GYB4HCZYXJZRLPOBB', - 'GD3KWA24OIM7V3MZKDAVSLN3NBHGKVURNJ72ZCTAJSDTF7RIGFXPW5FQ' => 'SBDNHDDICLLMBIDZ2IF2D3LH44OVUGGAVHQVQ6BZQI5IQO6AB6KNJCOV', - 'GB3C6RRQB3V7EPDXEDJCMTS45LVDLSZQ46PTIGKZUY37DXXEOAKJIWSV' => 'SDHRG2J34MGDAYHMOVKVJC6LX2QZMCTIKRO5I4JQ6BJQ36KVL6QUTT72', - ] - ], - [ - 'bench hurt jump file august wise shallow faculty impulse spring exact slush thunder author capable act festival slice deposit sauce coconut afford frown better', - '', - '937ae91f6ab6f12461d9936dfc1375ea5312d097f3f1eb6fed6a82fbe38c85824da8704389831482db0433e5f6c6c9700ff1946aa75ad8cc2654d6e40f567866', - 'df474e0dc2711089b89af6b089aceeb77e73120e9f895bd330a36fa952835ea8', - [ - 'GC3MMSXBWHL6CPOAVERSJITX7BH76YU252WGLUOM5CJX3E7UCYZBTPJQ' => 'SAEWIVK3VLNEJ3WEJRZXQGDAS5NVG2BYSYDFRSH4GKVTS5RXNVED5AX7', - 'GB3MTYFXPBZBUINVG72XR7AQ6P2I32CYSXWNRKJ2PV5H5C7EAM5YYISO' => 'SBKSABCPDWXDFSZISAVJ5XKVIEWV4M5O3KBRRLSPY3COQI7ZP423FYB4', - 'GDYF7GIHS2TRGJ5WW4MZ4ELIUIBINRNYPPAWVQBPLAZXC2JRDI4DGAKU' => 'SD5CCQAFRIPB3BWBHQYQ5SC66IB2AVMFNWWPBYGSUXVRZNCIRJ7IHESQ', - 'GAFLH7DGM3VXFVUID7JUKSGOYG52ZRAQPZHQASVCEQERYC5I4PPJUWBD' => 'SBSGSAIKEF7JYQWQSGXKB4SRHNSKDXTEI33WZDRR6UHYQCQ5I6ZGZQPK', - 'GAXG3LWEXWCAWUABRO6SMAEUKJXLB5BBX6J2KMHFRIWKAMDJKCFGS3NN' => 'SBIZH53PIRFTPI73JG7QYA3YAINOAT2XMNAUARB3QOWWVZVBAROHGXWM', - 'GA6RUD4DZ2NEMAQY4VZJ4C6K6VSEYEJITNSLUQKLCFHJ2JOGC5UCGCFQ' => 'SCVM6ZNVRUOP4NMCMMKLTVBEMAF2THIOMHPYSSMPCD2ZU7VDPARQQ6OY', - 'GCUDW6ZF5SCGCMS3QUTELZ6LSAH6IVVXNRPRLAUNJ2XYLCA7KH7ZCVQS' => 'SBSHUZQNC45IAIRSAHMWJEJ35RY7YNW6SMOEBZHTMMG64NKV7Y52ZEO2', - 'GBJ646Q524WGBN5X5NOAPIF5VQCR2WZCN6QZIDOSY6VA2PMHJ2X636G4' => 'SC2QO2K2B4EBNBJMBZIKOYSHEX4EZAZNIF4UNLH63AQYV6BE7SMYWC6E', - 'GDHX4LU6YBSXGYTR7SX2P4ZYZSN24VXNJBVAFOB2GEBKNN3I54IYSRM4' => 'SCGMC5AHAAVB3D4JXQPCORWW37T44XJZUNPEMLRW6DCOEARY3H5MAQST', - 'GDXOY6HXPIDT2QD352CH7VWX257PHVFR72COWQ74QE3TEV4PK2KCKZX7' => 'SCPA5OX4EYINOPAUEQCPY6TJMYICUS5M7TVXYKWXR3G5ZRAJXY3C37GF', - ] - ], - [ - 'cable spray genius state float twenty onion head street palace net private method loan turn phrase state blanket interest dry amazing dress blast tube', - 'p4ssphr4se', - 'd425d39998fb42ce4cf31425f0eaec2f0a68f47655ea030d6d26e70200d8ff8bd4326b4bdf562ea8640a1501ae93ccd0fd7992116da5dfa24900e570a742a489', - 'c83c61dc97d37832f0f20e258c3ba4040a258800fd14abaff124a4dee114b17e', - [ - 'GDAHPZ2NSYIIHZXM56Y36SBVTV5QKFIZGYMMBHOU53ETUSWTP62B63EQ' => 'SAFWTGXVS7ELMNCXELFWCFZOPMHUZ5LXNBGUVRCY3FHLFPXK4QPXYP2X', - 'GDY47CJARRHHL66JH3RJURDYXAMIQ5DMXZLP3TDAUJ6IN2GUOFX4OJOC' => 'SBQPDFUGLMWJYEYXFRM5TQX3AX2BR47WKI4FDS7EJQUSEUUVY72MZPJF', - 'GCLAQF5H5LGJ2A6ACOMNEHSWYDJ3VKVBUBHDWFGRBEPAVZ56L4D7JJID' => 'SAF2LXRW6FOSVQNC4HHIIDURZL4SCGCG7UEGG23ZQG6Q2DKIGMPZV6BZ', - 'GBC36J4KG7ZSIQ5UOSJFQNUP4IBRN6LVUFAHQWT2ODEQ7Y3ASWC5ZN3B' => 'SDCCVBIYZDMXOR4VPC3IYMIPODNEDZCS44LDN7B5ZWECIE57N3BTV4GQ', - 'GA6NHA4KPH5LFYD6LZH35SIX3DU5CWU3GX6GCKPJPPTQCCQPP627E3CB' => 'SA5TRXTO7BG2Z6QTQT3O2LC7A7DLZZ2RBTGUNCTG346PLVSSHXPNDVNT', - 'GBOWMXTLABFNEWO34UJNSJJNVEF6ESLCNNS36S5SX46UZT2MNYJOLA5L' => 'SDEOED2KPHV355YNOLLDLVQB7HDPQVIGKXCAJMA3HTM4325ZHFZSKKUC', - 'GBL3F5JUZN3SQKZ7SL4XSXEJI2SNSVGO6WZWNJLG666WOJHNDDLEXTSZ' => 'SDYNO6TLFNV3IM6THLNGUG5FII4ET2H7NH3KCT6OAHIUSHKR4XBEEI6A', - 'GA5XPPWXL22HFFL5K5CE37CEPUHXYGSP3NNWGM6IK6K4C3EFHZFKSAND' => 'SDXMJXAY45W3WEFWMYEPLPIF4CXAD5ECQ37XKMGY5EKLM472SSRJXCYD', - 'GDS5I7L7LWFUVSYVAOHXJET2565MGGHJ4VHGVJXIKVKNO5D4JWXIZ3XU' => 'SAIZA26BUP55TDCJ4U7I2MSQEAJDPDSZSBKBPWQTD5OQZQSJAGNN2IQB', - 'GBOSMFQYKWFDHJWCMCZSMGUMWCZOM4KFMXXS64INDHVCJ2A2JAABCYRR' => 'SDXDYPDNRMGOF25AWYYKPHFAD3M54IT7LCLG7RWTGR3TS32A4HTUXNOS', - ] - ], - ]; - } +assertEquals($publicKey, $keypair->getPublicKey()); + $this->assertEquals($privateKey, $keypair->getSecret()); + } + public function newKeypairFromMnemonicProvider() + { + return [ + [ + 'cable spray genius state float twenty onion head street palace net private method loan turn phrase state blanket interest dry amazing dress blast tube', + 'p4ssphr4se', + 'GDAHPZ2NSYIIHZXM56Y36SBVTV5QKFIZGYMMBHOU53ETUSWTP62B63EQ', + 'SAFWTGXVS7ELMNCXELFWCFZOPMHUZ5LXNBGUVRCY3FHLFPXK4QPXYP2X', + ], + ]; + } + + /** + * @dataProvider sep0005Provider + */ + public function testSep0005($mnemonic, $passphrase, $masterSeedHex, $addressNodeKeyHex, $keys) + { + print "\n"; + + $bip39 = new Bip39(); + $seedBytes = $bip39->mnemonicToSeedBytesWithErrorChecking($mnemonic, $passphrase); + $this->assertEquals(bin2hex($seedBytes), $masterSeedHex); + + $masterNode = HdNode::newMasterNode($seedBytes); + $addressNode = $masterNode->derivePath("m/44'/148'"); + $this->assertEquals($addressNodeKeyHex, bin2hex($addressNode->getPrivateKeyBytes())); + + $keyIdx = 0; + foreach ($keys as $publicString => $privateString) { + $accountNode = $addressNode->derive($keyIdx); + $keypair = Keypair::newFromRawSeed($accountNode->getPrivateKeyBytes()); + + $this->assertEquals($publicString, $keypair->getPublicKey()); + $this->assertEquals($privateString, $keypair->getSecret()); + + $keyIdx++; + } + } + public function sep0005Provider() + { + return [ + // From entropy bytes 00000000000000000000000000000000 + [ + 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about', + '', + '5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4', + '03df7921b4f789040e361d07d5e4eddad277c376350d7b5d585400a0ef18f2f5', + [ + 'GB3JDWCQJCWMJ3IILWIGDTQJJC5567PGVEVXSCVPEQOTDN64VJBDQBYX' => 'SBUV3MRWKNS6AYKZ6E6MOUVF2OYMON3MIUASWL3JLY5E3ISDJFELYBRZ', + 'GDVSYYTUAJ3ACHTPQNSTQBDQ4LDHQCMNY4FCEQH5TJUMSSLWQSTG42MV' => 'SCHDCVCWGAKGIMTORV6K5DYYV3BY4WG3RA4M6MCBGJLHUCWU2MC6DL66', + 'GBFPWBTN4AXHPWPTQVQBP4KRZ2YVYYOGRMV2PEYL2OBPPJDP7LECEVHR' => 'SAPLVTLUXSDLFRDGCCFLPDZMTCEVMP3ZXTM74EBJCVKZKM34LGQPF7K3', + 'GCCCOWAKYVFY5M6SYHOW33TSNC7Z5IBRUEU2XQVVT34CIZU7CXZ4OQ4O' => 'SDQYXOP2EAUZP4YOEQ5BUJIQ3RDSP5XV4ZFI6C5Y3QCD5Y63LWPXT7PW', + 'GCQ3J35MKPKJX7JDXRHC5YTXTULFMCBMZ5IC63EDR66QA3LO7264ZL7Q' => 'SCT7DUHYZD6DRCETT6M73GWKFJI4D56P3SNWNWNJ7ANLJZS6XIFYYXSB', + 'GDTA7622ZA5PW7F7JL7NOEFGW62M7GW2GY764EQC2TUJ42YJQE2A3QUL' => 'SDTWG5AFDI6GRQNLPWOC7IYS7AKOGMI2GX4OXTBTZHHYPMNZ2PX4ONWU', + 'GD7A7EACTPTBCYCURD43IEZXGIBCEXNBHN3OFWV2FOX67XKUIGRCTBNU' => 'SDJMWY4KFRS4PTA5WBFVCPS2GKYLXOMCLQSBNEIBG7KRGHNQOM25KMCP', + 'GAF4AGPVLQXFKEWQV3DZU5YEFU6YP7XJHAEEQH4G3R664MSF77FLLRK3' => 'SDOJH5JRCNGT57QTPTJEQGBEBZJPXE7XUDYDB24VTOPP7PH3ALKHAHFG', + 'GABTYCZJMCP55SS6I46SR76IHETZDLG4L37MLZRZKQDGBLS5RMP65TSX' => 'SC6N6GYQ2VA4T7CUP2BWGBRT2P6L2HQSZIUNQRHNDLISF6ND7TW4P4ER', + 'GAKFARYSPI33KUJE7HYLT47DCX2PFWJ77W3LZMRBPSGPGYPMSDBE7W7X' => 'SALJ5LPBTXCFML2CQ7ORP7WJNJOZSVBVRQAAODMVHMUF4P4XXFZB7MKY', + ] + ], + [ + 'illness spike retreat truth genius clock brain pass fit cave bargain toe', + '', + 'e4a5a632e70943ae7f07659df1332160937fad82587216a4c64315a0fb39497ee4a01f76ddab4cba68147977f3a147b6ad584c41808e8238a07f6cc4b582f186', + 'e0eec84fe165cd427cb7bc9b6cfdef0555aa1cb6f9043ff1fe986c3c8ddd22e3', + [ + 'GDRXE2BQUC3AZNPVFSCEZ76NJ3WWL25FYFK6RGZGIEKWE4SOOHSUJUJ6' => 'SBGWSG6BTNCKCOB3DIFBGCVMUPQFYPA2G4O34RMTB343OYPXU5DJDVMN', + 'GBAW5XGWORWVFE2XTJYDTLDHXTY2Q2MO73HYCGB3XMFMQ562Q2W2GJQX' => 'SCEPFFWGAG5P2VX5DHIYK3XEMZYLTYWIPWYEKXFHSK25RVMIUNJ7CTIS', + 'GAY5PRAHJ2HIYBYCLZXTHID6SPVELOOYH2LBPH3LD4RUMXUW3DOYTLXW' => 'SDAILLEZCSA67DUEP3XUPZJ7NYG7KGVRM46XA7K5QWWUIGADUZCZWTJP', + 'GAOD5NRAEORFE34G5D4EOSKIJB6V4Z2FGPBCJNQI6MNICVITE6CSYIAE' => 'SBMWLNV75BPI2VB4G27RWOMABVRTSSF7352CCYGVELZDSHCXWCYFKXIX', + 'GBCUXLFLSL2JE3NWLHAWXQZN6SQC6577YMAU3M3BEMWKYPFWXBSRCWV4' => 'SCPCY3CEHMOP2TADSV2ERNNZBNHBGP4V32VGOORIEV6QJLXD5NMCJUXI', + 'GBRQY5JFN5UBG5PGOSUOL4M6D7VRMAYU6WW2ZWXBMCKB7GPT3YCBU2XZ' => 'SCK27SFHI3WUDOEMJREV7ZJQG34SCBR6YWCE6OLEXUS2VVYTSNGCRS6X', + 'GBY27SJVFEWR3DUACNBSMJB6T4ZPR4C7ZXSTHT6GMZUDL23LAM5S2PQX' => 'SDJ4WDPOQAJYR3YIAJOJP3E6E4BMRB7VZ4QAEGCP7EYVDW6NQD3LRJMZ', + 'GAY7T23Z34DWLSTEAUKVBPHHBUE4E3EMZBAQSLV6ZHS764U3TKUSNJOF' => 'SA3HXJUCE2N27TBIZ5JRBLEBF3TLPQEBINP47E6BTMIWW2RJ5UKR2B3L', + 'GDJTCF62UUYSAFAVIXHPRBR4AUZV6NYJR75INVDXLLRZLZQ62S44443R' => 'SCD5OSHUUC75MSJG44BAT3HFZL2HZMMQ5M4GPDL7KA6HJHV3FLMUJAME', + 'GBTVYYDIYWGUQUTKX6ZMLGSZGMTESJYJKJWAATGZGITA25ZB6T5REF44' => 'SCJGVMJ66WAUHQHNLMWDFGY2E72QKSI3XGSBYV6BANDFUFE7VY4XNXXR', + ] + ], + [ + 'resource asthma orphan phone ice canvas fire useful arch jewel impose vague theory cushion top', + '', + '7b36d4e725b48695c3ffd2b4b317d5552cb157c1a26c46d36a05317f0d3053eb8b3b6496ba39ebd9312d10e3f9937b47a6790541e7c577da027a564862e92811', + '2e5d4e6b54a4b96c5e887c9ec92f619a3c134d8b1059dcef15c1a9b228ae3751', + [ + 'GAVXVW5MCK7Q66RIBWZZKZEDQTRXWCZUP4DIIFXCCENGW2P6W4OA34RH' => 'SAKS7I2PNDBE5SJSUSU2XLJ7K5XJ3V3K4UDFAHMSBQYPOKE247VHAGDB', + 'GDFCYVCICATX5YPJUDS22KM2GW5QU2KKSPPPT2IC5AQIU6TP3BZSLR5K' => 'SAZ2H5GLAVWCUWNPQMB6I3OHRI63T2ACUUAWSH7NAGYYPXGIOPLPW3Q4', + 'GAUA3XK3SGEQFNCBM423WIM5WCZ4CR4ZDPDFCYSFLCTODGGGJMPOHAAE' => 'SDVSSLPL76I33DKAI4LFTOAKCHJNCXUERGPCMVFT655Z4GRLWM6ZZTSC', + 'GAH3S77QXTAPZ77REY6LGFIJ2XWVXFOKXHCFLA6HQTL3POLVZJDHHUDM' => 'SCH56YSGOBYVBC6DO3ZI2PY62GBVXT4SEJSXJOBQYGC2GCEZSB5PEVBZ', + 'GCSCZVGV2Y3EQ2RATJ7TE6PVWTW5OH5SMG754AF6W6YM3KJF7RMNPB4Y' => 'SBWBM73VUNBGBMFD4E2BA7Q756AKVEAAVTQH34RYEUFD6X64VYL5KXQ2', + 'GDKWYAJE3W6PWCXDZNMFNFQSPTF6BUDANE6OVRYMJKBYNGL62VKKCNCC' => 'SAVS4CDQZI6PSA5DPCC42S5WLKYIPKXPCJSFYY4N3VDK25T2XX2BTGVX', + 'GCDTVB4XDLNX22HI5GUWHBXJFBCPB6JNU6ZON7E57FA3LFURS74CWDJH' => 'SDFC7WZT3GDQVQUQMXN7TC7UWDW5E3GSMFPHUT2TSTQ7RKWTRA4PLBAL', + 'GBTDPL5S4IOUQHDLCZ7I2UXJ2TEHO6DYIQ3F2P5OOP3IS7JSJI4UMHQJ' => 'SA6UO2FIYC6AS2MSDECLR6F7NKCJTG67F7R4LV2GYB4HCZYXJZRLPOBB', + 'GD3KWA24OIM7V3MZKDAVSLN3NBHGKVURNJ72ZCTAJSDTF7RIGFXPW5FQ' => 'SBDNHDDICLLMBIDZ2IF2D3LH44OVUGGAVHQVQ6BZQI5IQO6AB6KNJCOV', + 'GB3C6RRQB3V7EPDXEDJCMTS45LVDLSZQ46PTIGKZUY37DXXEOAKJIWSV' => 'SDHRG2J34MGDAYHMOVKVJC6LX2QZMCTIKRO5I4JQ6BJQ36KVL6QUTT72', + ] + ], + [ + 'bench hurt jump file august wise shallow faculty impulse spring exact slush thunder author capable act festival slice deposit sauce coconut afford frown better', + '', + '937ae91f6ab6f12461d9936dfc1375ea5312d097f3f1eb6fed6a82fbe38c85824da8704389831482db0433e5f6c6c9700ff1946aa75ad8cc2654d6e40f567866', + 'df474e0dc2711089b89af6b089aceeb77e73120e9f895bd330a36fa952835ea8', + [ + 'GC3MMSXBWHL6CPOAVERSJITX7BH76YU252WGLUOM5CJX3E7UCYZBTPJQ' => 'SAEWIVK3VLNEJ3WEJRZXQGDAS5NVG2BYSYDFRSH4GKVTS5RXNVED5AX7', + 'GB3MTYFXPBZBUINVG72XR7AQ6P2I32CYSXWNRKJ2PV5H5C7EAM5YYISO' => 'SBKSABCPDWXDFSZISAVJ5XKVIEWV4M5O3KBRRLSPY3COQI7ZP423FYB4', + 'GDYF7GIHS2TRGJ5WW4MZ4ELIUIBINRNYPPAWVQBPLAZXC2JRDI4DGAKU' => 'SD5CCQAFRIPB3BWBHQYQ5SC66IB2AVMFNWWPBYGSUXVRZNCIRJ7IHESQ', + 'GAFLH7DGM3VXFVUID7JUKSGOYG52ZRAQPZHQASVCEQERYC5I4PPJUWBD' => 'SBSGSAIKEF7JYQWQSGXKB4SRHNSKDXTEI33WZDRR6UHYQCQ5I6ZGZQPK', + 'GAXG3LWEXWCAWUABRO6SMAEUKJXLB5BBX6J2KMHFRIWKAMDJKCFGS3NN' => 'SBIZH53PIRFTPI73JG7QYA3YAINOAT2XMNAUARB3QOWWVZVBAROHGXWM', + 'GA6RUD4DZ2NEMAQY4VZJ4C6K6VSEYEJITNSLUQKLCFHJ2JOGC5UCGCFQ' => 'SCVM6ZNVRUOP4NMCMMKLTVBEMAF2THIOMHPYSSMPCD2ZU7VDPARQQ6OY', + 'GCUDW6ZF5SCGCMS3QUTELZ6LSAH6IVVXNRPRLAUNJ2XYLCA7KH7ZCVQS' => 'SBSHUZQNC45IAIRSAHMWJEJ35RY7YNW6SMOEBZHTMMG64NKV7Y52ZEO2', + 'GBJ646Q524WGBN5X5NOAPIF5VQCR2WZCN6QZIDOSY6VA2PMHJ2X636G4' => 'SC2QO2K2B4EBNBJMBZIKOYSHEX4EZAZNIF4UNLH63AQYV6BE7SMYWC6E', + 'GDHX4LU6YBSXGYTR7SX2P4ZYZSN24VXNJBVAFOB2GEBKNN3I54IYSRM4' => 'SCGMC5AHAAVB3D4JXQPCORWW37T44XJZUNPEMLRW6DCOEARY3H5MAQST', + 'GDXOY6HXPIDT2QD352CH7VWX257PHVFR72COWQ74QE3TEV4PK2KCKZX7' => 'SCPA5OX4EYINOPAUEQCPY6TJMYICUS5M7TVXYKWXR3G5ZRAJXY3C37GF', + ] + ], + [ + 'cable spray genius state float twenty onion head street palace net private method loan turn phrase state blanket interest dry amazing dress blast tube', + 'p4ssphr4se', + 'd425d39998fb42ce4cf31425f0eaec2f0a68f47655ea030d6d26e70200d8ff8bd4326b4bdf562ea8640a1501ae93ccd0fd7992116da5dfa24900e570a742a489', + 'c83c61dc97d37832f0f20e258c3ba4040a258800fd14abaff124a4dee114b17e', + [ + 'GDAHPZ2NSYIIHZXM56Y36SBVTV5QKFIZGYMMBHOU53ETUSWTP62B63EQ' => 'SAFWTGXVS7ELMNCXELFWCFZOPMHUZ5LXNBGUVRCY3FHLFPXK4QPXYP2X', + 'GDY47CJARRHHL66JH3RJURDYXAMIQ5DMXZLP3TDAUJ6IN2GUOFX4OJOC' => 'SBQPDFUGLMWJYEYXFRM5TQX3AX2BR47WKI4FDS7EJQUSEUUVY72MZPJF', + 'GCLAQF5H5LGJ2A6ACOMNEHSWYDJ3VKVBUBHDWFGRBEPAVZ56L4D7JJID' => 'SAF2LXRW6FOSVQNC4HHIIDURZL4SCGCG7UEGG23ZQG6Q2DKIGMPZV6BZ', + 'GBC36J4KG7ZSIQ5UOSJFQNUP4IBRN6LVUFAHQWT2ODEQ7Y3ASWC5ZN3B' => 'SDCCVBIYZDMXOR4VPC3IYMIPODNEDZCS44LDN7B5ZWECIE57N3BTV4GQ', + 'GA6NHA4KPH5LFYD6LZH35SIX3DU5CWU3GX6GCKPJPPTQCCQPP627E3CB' => 'SA5TRXTO7BG2Z6QTQT3O2LC7A7DLZZ2RBTGUNCTG346PLVSSHXPNDVNT', + 'GBOWMXTLABFNEWO34UJNSJJNVEF6ESLCNNS36S5SX46UZT2MNYJOLA5L' => 'SDEOED2KPHV355YNOLLDLVQB7HDPQVIGKXCAJMA3HTM4325ZHFZSKKUC', + 'GBL3F5JUZN3SQKZ7SL4XSXEJI2SNSVGO6WZWNJLG666WOJHNDDLEXTSZ' => 'SDYNO6TLFNV3IM6THLNGUG5FII4ET2H7NH3KCT6OAHIUSHKR4XBEEI6A', + 'GA5XPPWXL22HFFL5K5CE37CEPUHXYGSP3NNWGM6IK6K4C3EFHZFKSAND' => 'SDXMJXAY45W3WEFWMYEPLPIF4CXAD5ECQ37XKMGY5EKLM472SSRJXCYD', + 'GDS5I7L7LWFUVSYVAOHXJET2565MGGHJ4VHGVJXIKVKNO5D4JWXIZ3XU' => 'SAIZA26BUP55TDCJ4U7I2MSQEAJDPDSZSBKBPWQTD5OQZQSJAGNN2IQB', + 'GBOSMFQYKWFDHJWCMCZSMGUMWCZOM4KFMXXS64INDHVCJ2A2JAABCYRR' => 'SDXDYPDNRMGOF25AWYYKPHFAD3M54IT7LCLG7RWTGR3TS32A4HTUXNOS', + ] + ], + ]; + } } \ No newline at end of file diff --git a/tests/Unit/Model/AccountPaymentOperationsTest.php b/tests/Unit/Model/AccountPaymentOperationsTest.php new file mode 100644 index 0000000..c344bc2 --- /dev/null +++ b/tests/Unit/Model/AccountPaymentOperationsTest.php @@ -0,0 +1,107 @@ + '12345', + 'account_id' => 'GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF', + 'sequence' => '1', + 'subentry_count' => 0, + 'thresholds' => ['low_threshold' => 0, 'med_threshold' => 0, 'high_threshold' => 0], + 'balances' => [], + 'status' => 200, + ]); + $account = Account::fromHorizonResponse(new HorizonResponse($accountJson)); + + // Dummy ApiClient that returns a payments feed with mixed types + $dummyClient = new class { + public function get($relativeUrl) + { + $payload = [ + '_embedded' => [ + 'records' => [ + // Should be ignored by getPaymentOperations + [ + 'id' => '1', + 'type' => Operation::TYPE_CREATE_ACCOUNT, + 'type_i' => 0, + 'account' => 'GCREATE', + 'funder' => 'GFUNDER', + 'starting_balance' => '100.0000000', + 'transaction_hash' => 'tx1', + ], + // Included (payment) + [ + 'id' => '2', + 'type' => Operation::TYPE_PAYMENT, + 'type_i' => 1, + 'source_account' => 'GSRC', + 'from' => 'GFROM', + 'to' => 'GTO', + 'asset_type' => 'native', + 'amount' => '12.0000000', + 'transaction_hash' => 'tx2', + ], + // Should be ignored by getPaymentOperations + [ + 'id' => '3', + 'type' => Operation::TYPE_ACCOUNT_MERGE, + 'type_i' => 8, + 'account' => 'GOLD', + 'into' => 'GNEW', + 'transaction_hash' => 'tx3', + ], + // Included (path_payment) + [ + 'id' => '4', + 'type' => Operation::TYPE_PATH_PAYMENT, + 'type_i' => 2, + 'from' => 'GFROM2', + 'to' => 'GTO2', + // destination asset + 'amount' => '5.0000000', + 'asset_type' => 'credit_alphanum4', + 'asset_code' => 'USD', + 'asset_issuer' => 'GISSUER', + // source asset and max + 'source_amount' => '6.0000000', + 'source_asset_type' => 'native', + 'source_asset_code' => null, + 'source_asset_issuer' => null, + 'source_max' => '6.0000000', + 'transaction_hash' => 'tx4', + ], + ], + ], + ]; + + return new HorizonResponse(json_encode($payload)); + } + }; + + $account->setApiClient($dummyClient); + + $ops = $account->getPaymentOperations(); + + $this->assertCount(2, $ops); + foreach ($ops as $op) { + $this->assertInstanceOf(AssetTransferInterface::class, $op); + $this->assertTrue(in_array($op->getAssetTransferType(), [Operation::TYPE_PAYMENT, Operation::TYPE_PATH_PAYMENT], true)); + } + } +} + diff --git a/tests/Unit/Model/AccountTest.php b/tests/Unit/Model/AccountTest.php index b44822d..229fd91 100644 --- a/tests/Unit/Model/AccountTest.php +++ b/tests/Unit/Model/AccountTest.php @@ -1,19 +1,19 @@ -assertTrue(Account::isValidAccount('GDRXE2BQUC3AZNPVFSCEZ76NJ3WWL25FYFK6RGZGIEKWE4SOOHSUJUJ6')); - - $this->assertFalse(Account::isValidAccount(null)); - $this->assertFalse(Account::isValidAccount('G123')); - } +assertTrue(Account::isValidAccount('GDRXE2BQUC3AZNPVFSCEZ76NJ3WWL25FYFK6RGZGIEKWE4SOOHSUJUJ6')); + + $this->assertFalse(Account::isValidAccount(null)); + $this->assertFalse(Account::isValidAccount('G123')); + } } \ No newline at end of file diff --git a/tests/Unit/Model/StellarAmountTest.php b/tests/Unit/Model/StellarAmountTest.php index 0b6af4f..6b9fd7c 100644 --- a/tests/Unit/Model/StellarAmountTest.php +++ b/tests/Unit/Model/StellarAmountTest.php @@ -4,7 +4,7 @@ namespace ZuluCrypto\StellarSdk\Test\Unit\Model; -use phpseclib\Math\BigInteger; +use phpseclib3\Math\BigInteger; use PHPUnit\Framework\TestCase; use ZuluCrypto\StellarSdk\Model\StellarAmount; @@ -46,11 +46,9 @@ public function testSmallValues() $this->assertEquals(0.0000001, (new StellarAmount(0.0000001))->getScaledValue()); } - /** - * @expectedException \InvalidArgumentException - */ public function testGetScaledValueTooBig() { + $this->expectException(\InvalidArgumentException::class); // Maximum number of XLM that can be held is 922337203685.4775807 $amount = new StellarAmount(922337203686); @@ -58,11 +56,10 @@ public function testGetScaledValueTooBig() $amount->getScaledValue(); } - /** - * @expectedException \InvalidArgumentException - */ public function testExceptionWhenNegative() { + $this->expectException(\InvalidArgumentException::class); $amount = new StellarAmount(-1); } -} \ No newline at end of file +} + diff --git a/tests/Unit/Transaction/TransactionTest.php b/tests/Unit/Transaction/TransactionTest.php index da3e4ec..ec131bb 100644 --- a/tests/Unit/Transaction/TransactionTest.php +++ b/tests/Unit/Transaction/TransactionTest.php @@ -1,42 +1,42 @@ -setSequenceNumber(new BigInteger(123)); - - $createAccountOp = new CreateAccountOp(new AccountId(Keypair::newFromRandom()), 100); - $sourceModel->addOperation($createAccountOp); - - $sourceModel->setLowerTimebound(new \DateTime('2018-01-01 00:00:00')); - $sourceModel->setUpperTimebound(new \DateTime('2018-12-31 00:00:00')); - $sourceModel->setTextMemo('test memo'); - - // Encode and then parse the resulting XDR - $parsed = Transaction::fromXdr(new XdrBuffer($sourceModel->toXdr())); - $parsedOps = $parsed->getOperations(); - - $this->assertCount(1, $parsedOps); - - $this->assertEquals($sourceKeypair->getAccountId(), $parsed->getSourceAccountId()->getAccountIdString()); - $this->assertEquals('test memo', $parsed->getMemo()->getValue()); - } +setSequenceNumber(new BigInteger(123)); + + $createAccountOp = new CreateAccountOp(new AccountId(Keypair::newFromRandom()), 100); + $sourceModel->addOperation($createAccountOp); + + $sourceModel->setLowerTimebound(new \DateTime('2018-01-01 00:00:00')); + $sourceModel->setUpperTimebound(new \DateTime('2018-12-31 00:00:00')); + $sourceModel->setTextMemo('test memo'); + + // Encode and then parse the resulting XDR + $parsed = Transaction::fromXdr(new XdrBuffer($sourceModel->toXdr())); + $parsedOps = $parsed->getOperations(); + + $this->assertCount(1, $parsedOps); + + $this->assertEquals($sourceKeypair->getAccountId(), $parsed->getSourceAccountId()->getAccountIdString()); + $this->assertEquals('test memo', $parsed->getMemo()->getValue()); + } } \ No newline at end of file diff --git a/tests/Unit/Xdr/XdrDecoderTest.php b/tests/Unit/Xdr/XdrDecoderTest.php index 1a2ad39..d694c8c 100644 --- a/tests/Unit/Xdr/XdrDecoderTest.php +++ b/tests/Unit/Xdr/XdrDecoderTest.php @@ -1,74 +1,74 @@ -assertEquals(0, XdrDecoder::unsignedInteger("\x00\x00\x00\x00")); - $this->assertEquals(4294967295, XdrDecoder::unsignedInteger("\xFF\xFF\xFF\xFF")); - - $this->assertEquals(268435456, XdrDecoder::unsignedInteger(XdrEncoder::unsignedInteger(268435456))); - } - - public function testSignedInteger() - { - $this->assertEquals(0, XdrDecoder::signedInteger("\x00\x00\x00\x00")); - $this->assertEquals(1, XdrDecoder::signedInteger("\x00\x00\x00\x01")); - $this->assertEquals(-1, XdrDecoder::signedInteger("\xFF\xFF\xFF\xFF")); - - $this->assertEquals(-1024, XdrDecoder::signedInteger(XdrEncoder::unsignedInteger(-1024))); - } - - public function testUnsignedInteger64() - { - $this->assertEquals(0, XdrDecoder::unsignedInteger64("\x00\x00\x00\x00\x00\x00\x00\x00")); - - $this->assertEquals(4294967295, XdrDecoder::unsignedInteger64("\x00\x00\x00\x00\xFF\xFF\xFF\xFF")); - - $this->assertEquals(72057594000000000, XdrDecoder::unsignedInteger64(XdrEncoder::unsignedInteger64(72057594000000000))); - $this->assertEquals(9223372036854775807, XdrDecoder::unsignedInteger64(XdrEncoder::unsignedInteger64(9223372036854775807))); - } - - public function testSignedInteger64() - { - $this->assertEquals(0, XdrDecoder::signedInteger64("\x00\x00\x00\x00\x00\x00\x00\x00")); - - $this->assertEquals(4294967295, XdrDecoder::signedInteger64("\x00\x00\x00\x00\xFF\xFF\xFF\xFF")); - - $this->assertEquals(-1, XdrDecoder::signedInteger64(XdrEncoder::signedInteger64(-1))); - $this->assertEquals(9223372036854775807, XdrDecoder::signedInteger64(XdrEncoder::signedInteger64(9223372036854775807))); - } - - public function testOpaqueFixed() - { - $this->assertBytesEqual('00 11 22', XdrDecoder::opaqueFixed("\x00\x11\x22\x33\x44\x55", 3)); - } - - public function testOpaqueVariable() - { - $this->assertBytesEqual('00 11 22', XdrDecoder::opaqueVariable("\x00\x00\x00\x03\x00\x11\x22\x00")); - } - - public function testBoolean() - { - $this->assertEquals(true, XdrDecoder::boolean("\x00\x00\x00\x01")); - $this->assertEquals(false, XdrDecoder::boolean("\x00\x00\x00\x00")); - } - - protected function assertBytesEqual($expectedString, $actualBytes) - { - $expectedBytes = ''; - $rawExpected = explode(' ', $expectedString); - foreach ($rawExpected as $raw) { - $expectedBytes .= hex2bin($raw); - } - - $this->assertEquals(hash('sha256', $expectedBytes), hash('sha256', $actualBytes)); - } +assertEquals(0, XdrDecoder::unsignedInteger("\x00\x00\x00\x00")); + $this->assertEquals(4294967295, XdrDecoder::unsignedInteger("\xFF\xFF\xFF\xFF")); + + $this->assertEquals(268435456, XdrDecoder::unsignedInteger(XdrEncoder::unsignedInteger(268435456))); + } + + public function testSignedInteger() + { + $this->assertEquals(0, XdrDecoder::signedInteger("\x00\x00\x00\x00")); + $this->assertEquals(1, XdrDecoder::signedInteger("\x00\x00\x00\x01")); + $this->assertEquals(-1, XdrDecoder::signedInteger("\xFF\xFF\xFF\xFF")); + + $this->assertEquals(-1024, XdrDecoder::signedInteger(XdrEncoder::unsignedInteger(-1024))); + } + + public function testUnsignedInteger64() + { + $this->assertEquals(0, XdrDecoder::unsignedInteger64("\x00\x00\x00\x00\x00\x00\x00\x00")); + + $this->assertEquals(4294967295, XdrDecoder::unsignedInteger64("\x00\x00\x00\x00\xFF\xFF\xFF\xFF")); + + $this->assertEquals(72057594000000000, XdrDecoder::unsignedInteger64(XdrEncoder::unsignedInteger64(72057594000000000))); + $this->assertEquals(9223372036854775807, XdrDecoder::unsignedInteger64(XdrEncoder::unsignedInteger64(9223372036854775807))); + } + + public function testSignedInteger64() + { + $this->assertEquals(0, XdrDecoder::signedInteger64("\x00\x00\x00\x00\x00\x00\x00\x00")); + + $this->assertEquals(4294967295, XdrDecoder::signedInteger64("\x00\x00\x00\x00\xFF\xFF\xFF\xFF")); + + $this->assertEquals(-1, XdrDecoder::signedInteger64(XdrEncoder::signedInteger64(-1))); + $this->assertEquals(9223372036854775807, XdrDecoder::signedInteger64(XdrEncoder::signedInteger64(9223372036854775807))); + } + + public function testOpaqueFixed() + { + $this->assertBytesEqual('00 11 22', XdrDecoder::opaqueFixed("\x00\x11\x22\x33\x44\x55", 3)); + } + + public function testOpaqueVariable() + { + $this->assertBytesEqual('00 11 22', XdrDecoder::opaqueVariable("\x00\x00\x00\x03\x00\x11\x22\x00")); + } + + public function testBoolean() + { + $this->assertEquals(true, XdrDecoder::boolean("\x00\x00\x00\x01")); + $this->assertEquals(false, XdrDecoder::boolean("\x00\x00\x00\x00")); + } + + protected function assertBytesEqual($expectedString, $actualBytes) + { + $expectedBytes = ''; + $rawExpected = explode(' ', $expectedString); + foreach ($rawExpected as $raw) { + $expectedBytes .= hex2bin($raw); + } + + $this->assertEquals(hash('sha256', $expectedBytes), hash('sha256', $actualBytes)); + } } \ No newline at end of file diff --git a/tests/Unit/Xdr/XdrEncoderTest.php b/tests/Unit/Xdr/XdrEncoderTest.php index 77e648e..6e3f6ad 100644 --- a/tests/Unit/Xdr/XdrEncoderTest.php +++ b/tests/Unit/Xdr/XdrEncoderTest.php @@ -1,70 +1,70 @@ -assertBytesEqual('00 00 00 00 00 00 00 64', XdrEncoder::signedBigInteger64(new BigInteger("100"))); - - // -1 - $this->assertBytesEqual('ff ff ff ff ff ff ff ff', XdrEncoder::signedBigInteger64(new BigInteger("-1"))); - - // MAX_INT - $this->assertBytesEqual('00 00 00 00 ff ff ff ff', XdrEncoder::signedBigInteger64(new BigInteger("4294967295"))); - - // MAX_INT + 1 - $this->assertBytesEqual('00 00 00 01 00 00 00 00', XdrEncoder::signedBigInteger64(new BigInteger("4294967296"))); - - // max positive signed int64 - $this->assertBytesEqual('7f ff ff ff ff ff ff ff', XdrEncoder::signedBigInteger64(new BigInteger("9223372036854775807"))); - - // max negative signed int64 - $this->assertBytesEqual('80 00 00 00 00 00 00 00', XdrEncoder::signedBigInteger64(new BigInteger("-9223372036854775808"))); - } - - public function testUnsignedBigInteger64() - { - // 100 - $this->assertBytesEqual('00 00 00 00 00 00 00 64', XdrEncoder::unsignedBigInteger64(new BigInteger("100"))); - - // 18446744073709551615 - $this->assertBytesEqual('ff ff ff ff ff ff ff ff', XdrEncoder::unsignedBigInteger64(new BigInteger("18446744073709551615"))); - - // MAX_INT - $this->assertBytesEqual('00 00 00 00 ff ff ff ff', XdrEncoder::unsignedBigInteger64(new BigInteger("4294967295"))); - - // MAX_INT + 1 - $this->assertBytesEqual('00 00 00 01 00 00 00 00', XdrEncoder::unsignedBigInteger64(new BigInteger("4294967296"))); - - // max positive signed int64 - $this->assertBytesEqual('7f ff ff ff ff ff ff ff', XdrEncoder::unsignedBigInteger64(new BigInteger("9223372036854775807"))); - } - - public function testOpaqueVariable() - { - // Test padding is applied when characters are not a multiple of 4 - $this->assertBytesEqual('00 00 00 05 31 32 33 34 35 00 00 00', XdrEncoder::opaqueVariable('12345')); - } - - - protected function assertBytesEqual($expectedString, $actualBytes) - { - $expectedBytes = ''; - $rawExpected = explode(' ', $expectedString); - foreach ($rawExpected as $raw) { - $expectedBytes .= hex2bin($raw); - } - - $this->assertEquals(hash('sha256', $expectedBytes), hash('sha256', $actualBytes)); - } +assertBytesEqual('00 00 00 00 00 00 00 64', XdrEncoder::signedBigInteger64(new BigInteger("100"))); + + // -1 + $this->assertBytesEqual('ff ff ff ff ff ff ff ff', XdrEncoder::signedBigInteger64(new BigInteger("-1"))); + + // MAX_INT + $this->assertBytesEqual('00 00 00 00 ff ff ff ff', XdrEncoder::signedBigInteger64(new BigInteger("4294967295"))); + + // MAX_INT + 1 + $this->assertBytesEqual('00 00 00 01 00 00 00 00', XdrEncoder::signedBigInteger64(new BigInteger("4294967296"))); + + // max positive signed int64 + $this->assertBytesEqual('7f ff ff ff ff ff ff ff', XdrEncoder::signedBigInteger64(new BigInteger("9223372036854775807"))); + + // max negative signed int64 + $this->assertBytesEqual('80 00 00 00 00 00 00 00', XdrEncoder::signedBigInteger64(new BigInteger("-9223372036854775808"))); + } + + public function testUnsignedBigInteger64() + { + // 100 + $this->assertBytesEqual('00 00 00 00 00 00 00 64', XdrEncoder::unsignedBigInteger64(new BigInteger("100"))); + + // 18446744073709551615 + $this->assertBytesEqual('ff ff ff ff ff ff ff ff', XdrEncoder::unsignedBigInteger64(new BigInteger("18446744073709551615"))); + + // MAX_INT + $this->assertBytesEqual('00 00 00 00 ff ff ff ff', XdrEncoder::unsignedBigInteger64(new BigInteger("4294967295"))); + + // MAX_INT + 1 + $this->assertBytesEqual('00 00 00 01 00 00 00 00', XdrEncoder::unsignedBigInteger64(new BigInteger("4294967296"))); + + // max positive signed int64 + $this->assertBytesEqual('7f ff ff ff ff ff ff ff', XdrEncoder::unsignedBigInteger64(new BigInteger("9223372036854775807"))); + } + + public function testOpaqueVariable() + { + // Test padding is applied when characters are not a multiple of 4 + $this->assertBytesEqual('00 00 00 05 31 32 33 34 35 00 00 00', XdrEncoder::opaqueVariable('12345')); + } + + + protected function assertBytesEqual($expectedString, $actualBytes) + { + $expectedBytes = ''; + $rawExpected = explode(' ', $expectedString); + foreach ($rawExpected as $raw) { + $expectedBytes .= hex2bin($raw); + } + + $this->assertEquals(hash('sha256', $expectedBytes), hash('sha256', $actualBytes)); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/AccountIdTest.php b/tests/Unit/XdrModel/AccountIdTest.php index 003d280..9dd0487 100644 --- a/tests/Unit/XdrModel/AccountIdTest.php +++ b/tests/Unit/XdrModel/AccountIdTest.php @@ -1,23 +1,23 @@ -toXdr())); - - $this->assertEquals(AccountId::KEY_TYPE_ED25519, $decoded->getKeyType()); - $this->assertEquals($accountId, $decoded->getAccountIdString()); - } +toXdr())); + + $this->assertEquals(AccountId::KEY_TYPE_ED25519, $decoded->getKeyType()); + $this->assertEquals($accountId, $decoded->getAccountIdString()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/AssetTest.php b/tests/Unit/XdrModel/AssetTest.php index c8ab7c4..da2ae8c 100644 --- a/tests/Unit/XdrModel/AssetTest.php +++ b/tests/Unit/XdrModel/AssetTest.php @@ -1,58 +1,58 @@ -toXdr())); - - $this->assertEquals($asset->getType(), $assetFromXdr->getType()); - } - - public function testCustomAsset4FromXdr() - { - $issuerKeypair = Keypair::newFromRandom(); - $asset = Asset::newCustomAsset('TEST', $issuerKeypair); - - $assetFromXdr = Asset::fromXdr(new XdrBuffer($asset->toXdr())); - - $this->assertEquals($asset->getType(), $assetFromXdr->getType()); - $this->assertEquals('TEST', $assetFromXdr->getAssetCode()); - $this->assertEquals($issuerKeypair->getPublicKey(), $assetFromXdr->getIssuer()->getAccountIdString()); - } - - public function testCustomAsset7FromXdr() - { - $issuerKeypair = Keypair::newFromRandom(); - $asset = Asset::newCustomAsset('TESTABC', $issuerKeypair); - - $assetFromXdr = Asset::fromXdr(new XdrBuffer($asset->toXdr())); - - $this->assertEquals($asset->getType(), $assetFromXdr->getType()); - $this->assertEquals('TESTABC', $assetFromXdr->getAssetCode()); - $this->assertEquals($issuerKeypair->getPublicKey(), $assetFromXdr->getIssuer()->getAccountIdString()); - } - - public function testCustomAsset12FromXdr() - { - $issuerKeypair = Keypair::newFromRandom(); - $asset = Asset::newCustomAsset('ABCDEFGHIJKL', $issuerKeypair); - - $assetFromXdr = Asset::fromXdr(new XdrBuffer($asset->toXdr())); - - $this->assertEquals($asset->getType(), $assetFromXdr->getType()); - $this->assertEquals('ABCDEFGHIJKL', $assetFromXdr->getAssetCode()); - $this->assertEquals($issuerKeypair->getPublicKey(), $assetFromXdr->getIssuer()->getAccountIdString()); - } +toXdr())); + + $this->assertEquals($asset->getType(), $assetFromXdr->getType()); + } + + public function testCustomAsset4FromXdr() + { + $issuerKeypair = Keypair::newFromRandom(); + $asset = Asset::newCustomAsset('TEST', $issuerKeypair); + + $assetFromXdr = Asset::fromXdr(new XdrBuffer($asset->toXdr())); + + $this->assertEquals($asset->getType(), $assetFromXdr->getType()); + $this->assertEquals('TEST', $assetFromXdr->getAssetCode()); + $this->assertEquals($issuerKeypair->getPublicKey(), $assetFromXdr->getIssuer()->getAccountIdString()); + } + + public function testCustomAsset7FromXdr() + { + $issuerKeypair = Keypair::newFromRandom(); + $asset = Asset::newCustomAsset('TESTABC', $issuerKeypair); + + $assetFromXdr = Asset::fromXdr(new XdrBuffer($asset->toXdr())); + + $this->assertEquals($asset->getType(), $assetFromXdr->getType()); + $this->assertEquals('TESTABC', $assetFromXdr->getAssetCode()); + $this->assertEquals($issuerKeypair->getPublicKey(), $assetFromXdr->getIssuer()->getAccountIdString()); + } + + public function testCustomAsset12FromXdr() + { + $issuerKeypair = Keypair::newFromRandom(); + $asset = Asset::newCustomAsset('ABCDEFGHIJKL', $issuerKeypair); + + $assetFromXdr = Asset::fromXdr(new XdrBuffer($asset->toXdr())); + + $this->assertEquals($asset->getType(), $assetFromXdr->getType()); + $this->assertEquals('ABCDEFGHIJKL', $assetFromXdr->getAssetCode()); + $this->assertEquals($issuerKeypair->getPublicKey(), $assetFromXdr->getIssuer()->getAccountIdString()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/AccountMergeOpTest.php b/tests/Unit/XdrModel/Operation/AccountMergeOpTest.php index db3f72b..5e90956 100644 --- a/tests/Unit/XdrModel/Operation/AccountMergeOpTest.php +++ b/tests/Unit/XdrModel/Operation/AccountMergeOpTest.php @@ -1,25 +1,25 @@ -toXdr())); - - $this->assertTrue($parsed instanceof AccountMergeOp); - $this->assertEquals($source->getDestination()->getAccountIdString(), $parsed->getDestination()->getAccountIdString()); - } +toXdr())); + + $this->assertTrue($parsed instanceof AccountMergeOp); + $this->assertEquals($source->getDestination()->getAccountIdString(), $parsed->getDestination()->getAccountIdString()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/AllowTrustOpTest.php b/tests/Unit/XdrModel/Operation/AllowTrustOpTest.php index 8498871..9b6caa6 100644 --- a/tests/Unit/XdrModel/Operation/AllowTrustOpTest.php +++ b/tests/Unit/XdrModel/Operation/AllowTrustOpTest.php @@ -1,30 +1,30 @@ -setIsAuthorized(true); - - /** @var AllowTrustOp $parsed */ - $parsed = Operation::fromXdr(new XdrBuffer($sourceOp->toXdr())); - - $this->assertTrue($parsed instanceof AllowTrustOp); - - $this->assertEquals('TST', $parsed->getAsset()->getAssetCode()); - $this->assertEquals($sourceOp->getTrustor()->getAccountIdString(), $parsed->getTrustor()->getAccountIdString()); - } +setIsAuthorized(true); + + /** @var AllowTrustOp $parsed */ + $parsed = Operation::fromXdr(new XdrBuffer($sourceOp->toXdr())); + + $this->assertTrue($parsed instanceof AllowTrustOp); + + $this->assertEquals('TST', $parsed->getAsset()->getAssetCode()); + $this->assertEquals($sourceOp->getTrustor()->getAccountIdString(), $parsed->getTrustor()->getAccountIdString()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/BumpSequenceOpTest.php b/tests/Unit/XdrModel/Operation/BumpSequenceOpTest.php index 25584b6..072afc8 100644 --- a/tests/Unit/XdrModel/Operation/BumpSequenceOpTest.php +++ b/tests/Unit/XdrModel/Operation/BumpSequenceOpTest.php @@ -1,25 +1,25 @@ -toXdr())); - - $this->assertTrue($parsed instanceof BumpSequenceOp); - $this->assertEquals($source->getBumpTo()->toString(), $parsed->getBumpTo()->toString()); - } +toXdr())); + + $this->assertTrue($parsed instanceof BumpSequenceOp); + $this->assertEquals($source->getBumpTo()->toString(), $parsed->getBumpTo()->toString()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/ChangeTrustOpTest.php b/tests/Unit/XdrModel/Operation/ChangeTrustOpTest.php index 1fe0a77..8e90b00 100644 --- a/tests/Unit/XdrModel/Operation/ChangeTrustOpTest.php +++ b/tests/Unit/XdrModel/Operation/ChangeTrustOpTest.php @@ -1,29 +1,29 @@ -toXdr())); - - $this->assertTrue($parsed instanceof ChangeTrustOp); - - $this->assertEquals('TRUST', $parsed->getAsset()->getAssetCode()); - $this->assertEquals(8888, $parsed->getLimit()->getScaledValue()); - } +toXdr())); + + $this->assertTrue($parsed instanceof ChangeTrustOp); + + $this->assertEquals('TRUST', $parsed->getAsset()->getAssetCode()); + $this->assertEquals(8888, $parsed->getLimit()->getScaledValue()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/CreateAccountOpTest.php b/tests/Unit/XdrModel/Operation/CreateAccountOpTest.php index 49a53a8..5dc1c28 100644 --- a/tests/Unit/XdrModel/Operation/CreateAccountOpTest.php +++ b/tests/Unit/XdrModel/Operation/CreateAccountOpTest.php @@ -1,33 +1,33 @@ -getAccountId()); - $source = new CreateAccountOp($newAccountId, 1000, $sourceAccountKeypair); - - /** @var CreateAccountOp $parsed */ - $parsed = Operation::fromXdr(new XdrBuffer($source->toXdr())); - - $this->assertTrue($parsed instanceof CreateAccountOp); - $this->assertEquals($sourceAccountKeypair->getAccountId(), $parsed->getSourceAccount()->getAccountIdString()); - - $this->assertEquals($source->getNewAccount()->getAccountIdString(), $parsed->getNewAccount()->getAccountIdString()); - $this->assertEquals($source->getStartingBalance()->getScaledValue(), $parsed->getStartingBalance()->getScaledValue()); - } +getAccountId()); + $source = new CreateAccountOp($newAccountId, 1000, $sourceAccountKeypair); + + /** @var CreateAccountOp $parsed */ + $parsed = Operation::fromXdr(new XdrBuffer($source->toXdr())); + + $this->assertTrue($parsed instanceof CreateAccountOp); + $this->assertEquals($sourceAccountKeypair->getAccountId(), $parsed->getSourceAccount()->getAccountIdString()); + + $this->assertEquals($source->getNewAccount()->getAccountIdString(), $parsed->getNewAccount()->getAccountIdString()); + $this->assertEquals($source->getStartingBalance()->getScaledValue(), $parsed->getStartingBalance()->getScaledValue()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/CreatePassiveOfferOpTest.php b/tests/Unit/XdrModel/Operation/CreatePassiveOfferOpTest.php index d039082..ae5d70a 100644 --- a/tests/Unit/XdrModel/Operation/CreatePassiveOfferOpTest.php +++ b/tests/Unit/XdrModel/Operation/CreatePassiveOfferOpTest.php @@ -1,41 +1,41 @@ -toXdr())); - - $this->assertTrue($parsed instanceof CreatePassiveOfferOp); - - $this->assertEquals($sellingAsset->getAssetCode(), $parsed->getSellingAsset()->getAssetCode()); - $this->assertEquals($buyingAsset->getAssetCode(), $parsed->getBuyingAsset()->getAssetCode()); - $this->assertEquals($amount, $parsed->getAmount()->getScaledValue()); - $this->assertEquals(.00025, $parsed->getPrice()->toFloat()); - } +toXdr())); + + $this->assertTrue($parsed instanceof CreatePassiveOfferOp); + + $this->assertEquals($sellingAsset->getAssetCode(), $parsed->getSellingAsset()->getAssetCode()); + $this->assertEquals($buyingAsset->getAssetCode(), $parsed->getBuyingAsset()->getAssetCode()); + $this->assertEquals($amount, $parsed->getAmount()->getScaledValue()); + $this->assertEquals(.00025, $parsed->getPrice()->toFloat()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/InflationOpTest.php b/tests/Unit/XdrModel/Operation/InflationOpTest.php index 8ca4413..9944fc0 100644 --- a/tests/Unit/XdrModel/Operation/InflationOpTest.php +++ b/tests/Unit/XdrModel/Operation/InflationOpTest.php @@ -1,25 +1,25 @@ -toXdr())); - - $this->assertTrue($parsed instanceof InflationOp); - } +toXdr())); + + $this->assertTrue($parsed instanceof InflationOp); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/ManageDataOpTest.php b/tests/Unit/XdrModel/Operation/ManageDataOpTest.php index e55386e..53af7e1 100644 --- a/tests/Unit/XdrModel/Operation/ManageDataOpTest.php +++ b/tests/Unit/XdrModel/Operation/ManageDataOpTest.php @@ -1,28 +1,28 @@ -toXdr())); - - $this->assertTrue($parsed instanceof ManageDataOp); - - $this->assertEquals('testkey', $parsed->getKey()); - $this->assertEquals('testvalue', $parsed->getValue()); - } +toXdr())); + + $this->assertTrue($parsed instanceof ManageDataOp); + + $this->assertEquals('testkey', $parsed->getKey()); + $this->assertEquals('testvalue', $parsed->getValue()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/ManageOfferOpTest.php b/tests/Unit/XdrModel/Operation/ManageOfferOpTest.php index a1ec4d1..cfb1632 100644 --- a/tests/Unit/XdrModel/Operation/ManageOfferOpTest.php +++ b/tests/Unit/XdrModel/Operation/ManageOfferOpTest.php @@ -1,44 +1,44 @@ -toXdr())); - - $this->assertTrue($parsed instanceof ManageOfferOp); - - $this->assertEquals($sellingAsset->getAssetCode(), $parsed->getSellingAsset()->getAssetCode()); - $this->assertEquals($buyingAsset->getAssetCode(), $parsed->getBuyingAsset()->getAssetCode()); - $this->assertEquals($amount, $parsed->getAmount()->getScaledValue()); - $this->assertEquals(.00025, $parsed->getPrice()->toFloat()); - $this->assertEquals($offerId, $parsed->getOfferId()); - } +toXdr())); + + $this->assertTrue($parsed instanceof ManageOfferOp); + + $this->assertEquals($sellingAsset->getAssetCode(), $parsed->getSellingAsset()->getAssetCode()); + $this->assertEquals($buyingAsset->getAssetCode(), $parsed->getBuyingAsset()->getAssetCode()); + $this->assertEquals($amount, $parsed->getAmount()->getScaledValue()); + $this->assertEquals(.00025, $parsed->getPrice()->toFloat()); + $this->assertEquals($offerId, $parsed->getOfferId()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/PathPaymentOpTest.php b/tests/Unit/XdrModel/Operation/PathPaymentOpTest.php index e247f83..f492e2e 100644 --- a/tests/Unit/XdrModel/Operation/PathPaymentOpTest.php +++ b/tests/Unit/XdrModel/Operation/PathPaymentOpTest.php @@ -1,43 +1,43 @@ -addPath($pathA); - $sourceOp->addPath($pathB); - - /** @var PathPaymentOp $parsed */ - $parsed = Operation::fromXdr(new XdrBuffer($sourceOp->toXdr())); - - $this->assertTrue($parsed instanceof PathPaymentOp); - - $this->assertEquals($sourceOp->getDestinationAccount()->getAccountIdString(), $parsed->getDestinationAccount()->getAccountIdString()); - $this->assertEquals($sendMax, $parsed->getSendMax()->getScaledValue()); - $this->assertEquals($destinationKeypair->getAccountId(), $parsed->getDestinationAccount()->getAccountIdString()); - $this->assertEquals($destinationAsset->getAssetCode(), $parsed->getDestinationAsset()->getAssetCode()); - $this->assertEquals($desinationAmount, $parsed->getDestinationAmount()->getScaledValue()); - } +addPath($pathA); + $sourceOp->addPath($pathB); + + /** @var PathPaymentOp $parsed */ + $parsed = Operation::fromXdr(new XdrBuffer($sourceOp->toXdr())); + + $this->assertTrue($parsed instanceof PathPaymentOp); + + $this->assertEquals($sourceOp->getDestinationAccount()->getAccountIdString(), $parsed->getDestinationAccount()->getAccountIdString()); + $this->assertEquals($sendMax, $parsed->getSendMax()->getScaledValue()); + $this->assertEquals($destinationKeypair->getAccountId(), $parsed->getDestinationAccount()->getAccountIdString()); + $this->assertEquals($destinationAsset->getAssetCode(), $parsed->getDestinationAsset()->getAssetCode()); + $this->assertEquals($desinationAmount, $parsed->getDestinationAmount()->getScaledValue()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/PaymentOpTest.php b/tests/Unit/XdrModel/Operation/PaymentOpTest.php index 41ba7f8..1be6bb7 100644 --- a/tests/Unit/XdrModel/Operation/PaymentOpTest.php +++ b/tests/Unit/XdrModel/Operation/PaymentOpTest.php @@ -1,34 +1,34 @@ -setDestination(new AccountId(Keypair::newFromRandom()->getAccountId())); - $sourceOp->setAmount(100); - $sourceOp->setAsset(Asset::newNativeAsset()); - - - /** @var PaymentOp $parsed */ - $parsed = Operation::fromXdr(new XdrBuffer($sourceOp->toXdr())); - - $this->assertTrue($parsed instanceof PaymentOp); - $this->assertEquals($sourceOp->getDestination()->getAccountIdString(), $parsed->getDestination()->getAccountIdString()); - $this->assertEquals($sourceOp->getAmount()->getScaledValue(), $parsed->getAmount()->getScaledValue()); - $this->assertEquals($sourceOp->getAsset()->getType(), $parsed->getAsset()->getType()); - } +setDestination(new AccountId(Keypair::newFromRandom()->getAccountId())); + $sourceOp->setAmount(100); + $sourceOp->setAsset(Asset::newNativeAsset()); + + + /** @var PaymentOp $parsed */ + $parsed = Operation::fromXdr(new XdrBuffer($sourceOp->toXdr())); + + $this->assertTrue($parsed instanceof PaymentOp); + $this->assertEquals($sourceOp->getDestination()->getAccountIdString(), $parsed->getDestination()->getAccountIdString()); + $this->assertEquals($sourceOp->getAmount()->getScaledValue(), $parsed->getAmount()->getScaledValue()); + $this->assertEquals($sourceOp->getAsset()->getType(), $parsed->getAsset()->getType()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/Operation/SetOptionsOpTest.php b/tests/Unit/XdrModel/Operation/SetOptionsOpTest.php index ad74bd7..6a115bb 100644 --- a/tests/Unit/XdrModel/Operation/SetOptionsOpTest.php +++ b/tests/Unit/XdrModel/Operation/SetOptionsOpTest.php @@ -1,66 +1,66 @@ -setAuthRequired(true); - $op->setAuthRevocable(false); - $this->assertTrue($op->isAuthRequired()); - $this->assertFalse($op->isAuthRevocable()); - } - - - public function testFromXdr() - { - $inflationDestinationKeypair = Keypair::newFromRandom(); - $masterWeight = 10; - $highThreshold = 9; - $mediumThreshold = 8; - $lowThreshold = 7; - $homeDomain = 'example.com'; - - $signer = new Signer(SignerKey::fromHashX('hashx'), 6); - - $sourceOp = new SetOptionsOp(); - $sourceOp->setInflationDestination($inflationDestinationKeypair->getPublicKey()); - $sourceOp->setAuthRequired(true); - $sourceOp->setAuthRevocable(false); - $sourceOp->setMasterWeight($masterWeight); - $sourceOp->setHighThreshold($highThreshold); - $sourceOp->setMediumThreshold($mediumThreshold); - $sourceOp->setLowThreshold($lowThreshold); - $sourceOp->setHomeDomain($homeDomain); - $sourceOp->updateSigner($signer); - - - /** @var SetOptionsOp $parsed */ - $parsed = Operation::fromXdr(new XdrBuffer($sourceOp->toXdr())); - - $this->assertTrue($parsed instanceof SetOptionsOp); - - $this->assertEquals($inflationDestinationKeypair->getAccountId(), $parsed->getInflationDestinationAccount()->getAccountIdString()); - $this->assertEquals(true, $parsed->isAuthRequired()); - $this->assertEquals(false, $parsed->isAuthRevocable()); - $this->assertEquals($masterWeight, $parsed->getMasterWeight()); - $this->assertEquals($highThreshold, $parsed->getHighThreshold()); - $this->assertEquals($mediumThreshold, $parsed->getMediumThreshold()); - $this->assertEquals($lowThreshold, $parsed->getLowThreshold()); - $this->assertEquals($homeDomain, $parsed->getHomeDomain()); - } +setAuthRequired(true); + $op->setAuthRevocable(false); + $this->assertTrue($op->isAuthRequired()); + $this->assertFalse($op->isAuthRevocable()); + } + + + public function testFromXdr() + { + $inflationDestinationKeypair = Keypair::newFromRandom(); + $masterWeight = 10; + $highThreshold = 9; + $mediumThreshold = 8; + $lowThreshold = 7; + $homeDomain = 'example.com'; + + $signer = new Signer(SignerKey::fromHashX('hashx'), 6); + + $sourceOp = new SetOptionsOp(); + $sourceOp->setInflationDestination($inflationDestinationKeypair->getPublicKey()); + $sourceOp->setAuthRequired(true); + $sourceOp->setAuthRevocable(false); + $sourceOp->setMasterWeight($masterWeight); + $sourceOp->setHighThreshold($highThreshold); + $sourceOp->setMediumThreshold($mediumThreshold); + $sourceOp->setLowThreshold($lowThreshold); + $sourceOp->setHomeDomain($homeDomain); + $sourceOp->updateSigner($signer); + + + /** @var SetOptionsOp $parsed */ + $parsed = Operation::fromXdr(new XdrBuffer($sourceOp->toXdr())); + + $this->assertTrue($parsed instanceof SetOptionsOp); + + $this->assertEquals($inflationDestinationKeypair->getAccountId(), $parsed->getInflationDestinationAccount()->getAccountIdString()); + $this->assertEquals(true, $parsed->isAuthRequired()); + $this->assertEquals(false, $parsed->isAuthRevocable()); + $this->assertEquals($masterWeight, $parsed->getMasterWeight()); + $this->assertEquals($highThreshold, $parsed->getHighThreshold()); + $this->assertEquals($mediumThreshold, $parsed->getMediumThreshold()); + $this->assertEquals($lowThreshold, $parsed->getLowThreshold()); + $this->assertEquals($homeDomain, $parsed->getHomeDomain()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/OperationResultTest.php b/tests/Unit/XdrModel/OperationResultTest.php index 0a23971..7e4a805 100644 --- a/tests/Unit/XdrModel/OperationResultTest.php +++ b/tests/Unit/XdrModel/OperationResultTest.php @@ -1,203 +1,203 @@ -assertTrue($result instanceof PaymentResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - $this->assertTrue($result->succeeded()); - $this->assertFalse($result->failed()); - } - - public function testCreateAccountOperationResultSuccess() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAAAAAAAAAAAAA==')); - - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof CreateAccountResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - } - - public function testPathPaymentOperationResultSuccess() - { - // https://www.stellar.org/laboratory/#xdr-viewer?input=AAAAAAAAAAIAAAAAAAAAAQAAAAAp9kRanuQMa2XlcQS2SWs5LRrVwEihfnrPyY6PrfiDTgAAAAAAAAACAAAAAkVVUlRFU1QAAAAAAAAAAABcI7sXin6ZN1piyUF6r8YxaAcf%2FgmNFo9NaZbbQGAQDgAAAAAAmJaAAAAAAAAAAABHhowAAAAAABbngwiocBzfacUJP37WCNTnSfiGub%2BhSsife4OHO5VMAAAAAkVVUlRFU1QAAAAAAAAAAABcI7sXin6ZN1piyUF6r8YxaAcf%2FgmNFo9NaZbbQGAQDgAAAAAAmJaAAAAAAA%3D%3D&type=OperationResult&network=test - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAIAAAAAAAAAAQAAAAAp9kRanuQMa2XlcQS2SWs5LRrVwEihfnrPyY6PrfiDTgAAAAAAAAACAAAAAkVVUlRFU1QAAAAAAAAAAABcI7sXin6ZN1piyUF6r8YxaAcf/gmNFo9NaZbbQGAQDgAAAAAAmJaAAAAAAAAAAABHhowAAAAAABbngwiocBzfacUJP37WCNTnSfiGub+hSsife4OHO5VMAAAAAkVVUlRFU1QAAAAAAAAAAABcI7sXin6ZN1piyUF6r8YxaAcf/gmNFo9NaZbbQGAQDgAAAAAAmJaAAAAAAA==')); - - /** @var PathPaymentResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof PathPaymentResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - - $this->assertEquals('GALOPAYIVBYBZX3JYUET67WWBDKOOSPYQ2437IKKZCPXXA4HHOKUZ5OA', $result->getDestination()->getAccountIdString()); - $this->assertEquals(1, $result->getPaidAmount()->getScaledValue()); - - $this->assertEquals('EURTEST', $result->getPaidAsset()->getAssetCode()); - $this->assertEquals('GBOCHOYXRJ7JSN22MLEUC6VPYYYWQBY77YEY2FUPJVUZNW2AMAIA5ISC', $result->getPaidAsset()->getIssuer()->getAccountIdString()); - - // There should be one matched offer - $claimedOffers = $result->getClaimedOffers(); - $this->assertCount(1, $claimedOffers); - - $offer = $claimedOffers[0]; - - $this->assertEquals('GAU7MRC2T3SAY23F4VYQJNSJNM4S2GWVYBEKC7T2Z7EY5D5N7CBU4QSH', $offer->getSeller()->getAccountIdString()); - $this->assertNotEmpty($offer->getOfferId()); - - $this->assertEquals('EURTEST', $offer->getAssetSold()->getAssetCode()); - $this->assertEquals('GBOCHOYXRJ7JSN22MLEUC6VPYYYWQBY77YEY2FUPJVUZNW2AMAIA5ISC', $offer->getAssetSold()->getIssuer()->getAccountIdString()); - $this->assertEquals(1, $offer->getAmountSold()->getScaledValue()); - - $this->assertEquals(Asset::TYPE_NATIVE, $offer->getAssetBought()->getType()); - $this->assertEquals(120, $offer->getAmountBought()->getScaledValue()); - } - - public function testManageOfferOperationResultCreate() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAZu10Z8p5vPaI2kYKQYdT9yrRS1hk1v5lj9ltvEt8rbkAAAAAAAAACAAAAAJVU0RURVNUAAAAAAAAAAAA0/c9zJnJQpAz9WkfgbePguOqP+8FnamSQyAubOcJB1EAAAAAAAAAAACYloAAAAACAAAAAQAAAAAAAAAAAAAAAA==')); - - /** @var ManageOfferResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof ManageOfferResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - - // Should be 0 offers claimed since this is a "create" - $this->assertCount(0, $result->getClaimedOffers()); - $this->assertNotEmpty($result->getOffer()->getOfferId()); - - $this->assertEquals('GBTO25DHZJ43Z5UI3JDAUQMHKP3SVUKLLBSNN7TFR7MW3PCLPSW3SFQQ', $result->getOffer()->getSeller()->getAccountIdString()); - $this->assertEquals('GDJ7OPOMTHEUFEBT6VUR7ANXR6BOHKR754CZ3KMSIMQC43HHBEDVDWVG', $result->getOffer()->getSellingAsset()->getIssuer()->getAccountIdString()); - - $this->assertEquals(Asset::TYPE_NATIVE, $result->getOffer()->getBuyingAsset()->getType()); - $this->assertEquals(1, $result->getOffer()->getSellingAmount()->getScaledValue()); - $this->assertEquals(2, $result->getOffer()->getPrice()->toFloat()); - } - - public function testManageOfferOperationResultUpdate() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAMAAAAAAAAAAAAAAAEAAAAAZu10Z8p5vPaI2kYKQYdT9yrRS1hk1v5lj9ltvEt8rbkAAAAAAAAACAAAAAJVU0RURVNUAAAAAAAAAAAA0/c9zJnJQpAz9WkfgbePguOqP+8FnamSQyAubOcJB1EAAAAAAAAAAACYloAAAAADAAAAAQAAAAAAAAAAAAAAAA==')); - - /** @var ManageOfferResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof ManageOfferResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - - // Should be 0 offers claimed since this is a "create" - $this->assertCount(0, $result->getClaimedOffers()); - $this->assertEquals(8, $result->getOffer()->getOfferId()); - - $this->assertEquals('GBTO25DHZJ43Z5UI3JDAUQMHKP3SVUKLLBSNN7TFR7MW3PCLPSW3SFQQ', $result->getOffer()->getSeller()->getAccountIdString()); - $this->assertEquals('GDJ7OPOMTHEUFEBT6VUR7ANXR6BOHKR754CZ3KMSIMQC43HHBEDVDWVG', $result->getOffer()->getSellingAsset()->getIssuer()->getAccountIdString()); - - $this->assertEquals(Asset::TYPE_NATIVE, $result->getOffer()->getBuyingAsset()->getType()); - $this->assertEquals(1, $result->getOffer()->getSellingAmount()->getScaledValue()); - $this->assertEquals(3, $result->getOffer()->getPrice()->toFloat()); - } - - public function testManageOfferOperationResultDelete() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAMAAAAAAAAAAAAAAAIAAAAA')); - - /** @var ManageOfferResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof ManageOfferResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - } - - public function testSetOptionsResultSuccess() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAUAAAAAAAAAAA==')); - - /** @var SetOptionsResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof SetOptionsResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - } - - public function testChangeTrustResultSuccess() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAYAAAAAAAAAAA==')); - - /** @var ChangeTrustResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof ChangeTrustResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - } - - public function testAllowTrustResultSuccess() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAcAAAAAAAAAAA==')); - - /** @var AllowTrustResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof AllowTrustResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - } - - public function testAccountMergeResultSuccess() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAgAAAAAAAAAAAHJwxwAAAAA')); - - /** @var AccountMergeResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof AccountMergeResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - - // Balance is 3 XLM - fee - $this->assertEquals(2.99999, $result->getTransferredBalance()->getScaledValue()); - } - - public function testInflationResultSuccess() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAkAAAAAAAAAAAAAAAA=')); - - /** @var InflationResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof InflationResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - } - - public function testManageDataResultSuccess() - { - $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAoAAAAAAAAAAA==')); - - /** @var ManageDataResult $result */ - $result = OperationResult::fromXdr($xdr); - - $this->assertTrue($result instanceof ManageDataResult, 'Incorrect class returned'); - $this->assertEquals(null, $result->getErrorCode()); - } +assertTrue($result instanceof PaymentResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + $this->assertTrue($result->succeeded()); + $this->assertFalse($result->failed()); + } + + public function testCreateAccountOperationResultSuccess() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAAAAAAAAAAAAA==')); + + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof CreateAccountResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + } + + public function testPathPaymentOperationResultSuccess() + { + // https://www.stellar.org/laboratory/#xdr-viewer?input=AAAAAAAAAAIAAAAAAAAAAQAAAAAp9kRanuQMa2XlcQS2SWs5LRrVwEihfnrPyY6PrfiDTgAAAAAAAAACAAAAAkVVUlRFU1QAAAAAAAAAAABcI7sXin6ZN1piyUF6r8YxaAcf%2FgmNFo9NaZbbQGAQDgAAAAAAmJaAAAAAAAAAAABHhowAAAAAABbngwiocBzfacUJP37WCNTnSfiGub%2BhSsife4OHO5VMAAAAAkVVUlRFU1QAAAAAAAAAAABcI7sXin6ZN1piyUF6r8YxaAcf%2FgmNFo9NaZbbQGAQDgAAAAAAmJaAAAAAAA%3D%3D&type=OperationResult&network=test + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAIAAAAAAAAAAQAAAAAp9kRanuQMa2XlcQS2SWs5LRrVwEihfnrPyY6PrfiDTgAAAAAAAAACAAAAAkVVUlRFU1QAAAAAAAAAAABcI7sXin6ZN1piyUF6r8YxaAcf/gmNFo9NaZbbQGAQDgAAAAAAmJaAAAAAAAAAAABHhowAAAAAABbngwiocBzfacUJP37WCNTnSfiGub+hSsife4OHO5VMAAAAAkVVUlRFU1QAAAAAAAAAAABcI7sXin6ZN1piyUF6r8YxaAcf/gmNFo9NaZbbQGAQDgAAAAAAmJaAAAAAAA==')); + + /** @var PathPaymentResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof PathPaymentResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + + $this->assertEquals('GALOPAYIVBYBZX3JYUET67WWBDKOOSPYQ2437IKKZCPXXA4HHOKUZ5OA', $result->getDestination()->getAccountIdString()); + $this->assertEquals(1, $result->getPaidAmount()->getScaledValue()); + + $this->assertEquals('EURTEST', $result->getPaidAsset()->getAssetCode()); + $this->assertEquals('GBOCHOYXRJ7JSN22MLEUC6VPYYYWQBY77YEY2FUPJVUZNW2AMAIA5ISC', $result->getPaidAsset()->getIssuer()->getAccountIdString()); + + // There should be one matched offer + $claimedOffers = $result->getClaimedOffers(); + $this->assertCount(1, $claimedOffers); + + $offer = $claimedOffers[0]; + + $this->assertEquals('GAU7MRC2T3SAY23F4VYQJNSJNM4S2GWVYBEKC7T2Z7EY5D5N7CBU4QSH', $offer->getSeller()->getAccountIdString()); + $this->assertNotEmpty($offer->getOfferId()); + + $this->assertEquals('EURTEST', $offer->getAssetSold()->getAssetCode()); + $this->assertEquals('GBOCHOYXRJ7JSN22MLEUC6VPYYYWQBY77YEY2FUPJVUZNW2AMAIA5ISC', $offer->getAssetSold()->getIssuer()->getAccountIdString()); + $this->assertEquals(1, $offer->getAmountSold()->getScaledValue()); + + $this->assertEquals(Asset::TYPE_NATIVE, $offer->getAssetBought()->getType()); + $this->assertEquals(120, $offer->getAmountBought()->getScaledValue()); + } + + public function testManageOfferOperationResultCreate() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAZu10Z8p5vPaI2kYKQYdT9yrRS1hk1v5lj9ltvEt8rbkAAAAAAAAACAAAAAJVU0RURVNUAAAAAAAAAAAA0/c9zJnJQpAz9WkfgbePguOqP+8FnamSQyAubOcJB1EAAAAAAAAAAACYloAAAAACAAAAAQAAAAAAAAAAAAAAAA==')); + + /** @var ManageOfferResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof ManageOfferResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + + // Should be 0 offers claimed since this is a "create" + $this->assertCount(0, $result->getClaimedOffers()); + $this->assertNotEmpty($result->getOffer()->getOfferId()); + + $this->assertEquals('GBTO25DHZJ43Z5UI3JDAUQMHKP3SVUKLLBSNN7TFR7MW3PCLPSW3SFQQ', $result->getOffer()->getSeller()->getAccountIdString()); + $this->assertEquals('GDJ7OPOMTHEUFEBT6VUR7ANXR6BOHKR754CZ3KMSIMQC43HHBEDVDWVG', $result->getOffer()->getSellingAsset()->getIssuer()->getAccountIdString()); + + $this->assertEquals(Asset::TYPE_NATIVE, $result->getOffer()->getBuyingAsset()->getType()); + $this->assertEquals(1, $result->getOffer()->getSellingAmount()->getScaledValue()); + $this->assertEquals(2, $result->getOffer()->getPrice()->toFloat()); + } + + public function testManageOfferOperationResultUpdate() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAMAAAAAAAAAAAAAAAEAAAAAZu10Z8p5vPaI2kYKQYdT9yrRS1hk1v5lj9ltvEt8rbkAAAAAAAAACAAAAAJVU0RURVNUAAAAAAAAAAAA0/c9zJnJQpAz9WkfgbePguOqP+8FnamSQyAubOcJB1EAAAAAAAAAAACYloAAAAADAAAAAQAAAAAAAAAAAAAAAA==')); + + /** @var ManageOfferResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof ManageOfferResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + + // Should be 0 offers claimed since this is a "create" + $this->assertCount(0, $result->getClaimedOffers()); + $this->assertEquals(8, $result->getOffer()->getOfferId()); + + $this->assertEquals('GBTO25DHZJ43Z5UI3JDAUQMHKP3SVUKLLBSNN7TFR7MW3PCLPSW3SFQQ', $result->getOffer()->getSeller()->getAccountIdString()); + $this->assertEquals('GDJ7OPOMTHEUFEBT6VUR7ANXR6BOHKR754CZ3KMSIMQC43HHBEDVDWVG', $result->getOffer()->getSellingAsset()->getIssuer()->getAccountIdString()); + + $this->assertEquals(Asset::TYPE_NATIVE, $result->getOffer()->getBuyingAsset()->getType()); + $this->assertEquals(1, $result->getOffer()->getSellingAmount()->getScaledValue()); + $this->assertEquals(3, $result->getOffer()->getPrice()->toFloat()); + } + + public function testManageOfferOperationResultDelete() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAMAAAAAAAAAAAAAAAIAAAAA')); + + /** @var ManageOfferResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof ManageOfferResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + } + + public function testSetOptionsResultSuccess() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAUAAAAAAAAAAA==')); + + /** @var SetOptionsResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof SetOptionsResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + } + + public function testChangeTrustResultSuccess() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAYAAAAAAAAAAA==')); + + /** @var ChangeTrustResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof ChangeTrustResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + } + + public function testAllowTrustResultSuccess() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAcAAAAAAAAAAA==')); + + /** @var AllowTrustResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof AllowTrustResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + } + + public function testAccountMergeResultSuccess() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAgAAAAAAAAAAAHJwxwAAAAA')); + + /** @var AccountMergeResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof AccountMergeResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + + // Balance is 3 XLM - fee + $this->assertEquals(2.99999, $result->getTransferredBalance()->getScaledValue()); + } + + public function testInflationResultSuccess() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAkAAAAAAAAAAAAAAAA=')); + + /** @var InflationResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof InflationResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + } + + public function testManageDataResultSuccess() + { + $xdr = new XdrBuffer(base64_decode('AAAAAAAAAAoAAAAAAAAAAA==')); + + /** @var ManageDataResult $result */ + $result = OperationResult::fromXdr($xdr); + + $this->assertTrue($result instanceof ManageDataResult, 'Incorrect class returned'); + $this->assertEquals(null, $result->getErrorCode()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/TimeBoundsTest.php b/tests/Unit/XdrModel/TimeBoundsTest.php index 6d7729c..89cb81d 100644 --- a/tests/Unit/XdrModel/TimeBoundsTest.php +++ b/tests/Unit/XdrModel/TimeBoundsTest.php @@ -1,22 +1,22 @@ -toXdr())); - - $this->assertEquals($source->getMinTimestamp(), $decoded->getMinTimestamp()); - $this->assertEquals($source->getMaxTimestamp(), $decoded->getMaxTimestamp()); - } +toXdr())); + + $this->assertEquals($source->getMinTimestamp(), $decoded->getMinTimestamp()); + $this->assertEquals($source->getMaxTimestamp(), $decoded->getMaxTimestamp()); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/TransactionEnvelopeTest.php b/tests/Unit/XdrModel/TransactionEnvelopeTest.php index 3b896c4..5dfa4ec 100644 --- a/tests/Unit/XdrModel/TransactionEnvelopeTest.php +++ b/tests/Unit/XdrModel/TransactionEnvelopeTest.php @@ -1,24 +1,24 @@ -getDecoratedSignatures(); - - $this->assertCount(1, $signatures); - } +getDecoratedSignatures(); + + $this->assertCount(1, $signatures); + } } \ No newline at end of file diff --git a/tests/Unit/XdrModel/TransactionResultTest.php b/tests/Unit/XdrModel/TransactionResultTest.php index 4167a52..2c85ec6 100644 --- a/tests/Unit/XdrModel/TransactionResultTest.php +++ b/tests/Unit/XdrModel/TransactionResultTest.php @@ -1,32 +1,32 @@ -getOperationResults(); - - $this->assertEquals(TransactionResult::SUCCESS, $result->getResultCode()); - $this->assertCount(1, $opResults); - $this->assertEquals(100, $result->getFeeCharged()->getUnscaledString()); - $this->assertTrue($result->succeeded()); - - $paymentResult = $opResults[0]; - $this->assertTrue($paymentResult instanceof PaymentResult); - $this->assertTrue($paymentResult->succeeded()); - } +getOperationResults(); + + $this->assertEquals(TransactionResult::SUCCESS, $result->getResultCode()); + $this->assertCount(1, $opResults); + $this->assertEquals(100, $result->getFeeCharged()->getUnscaledString()); + $this->assertTrue($result->succeeded()); + + $paymentResult = $opResults[0]; + $this->assertTrue($paymentResult instanceof PaymentResult); + $this->assertTrue($paymentResult->succeeded()); + } } \ No newline at end of file diff --git a/tests/Util/HardwareWalletIntegrationTest.php b/tests/Util/HardwareWalletIntegrationTest.php index e04c439..f153d2f 100644 --- a/tests/Util/HardwareWalletIntegrationTest.php +++ b/tests/Util/HardwareWalletIntegrationTest.php @@ -1,101 +1,101 @@ -mnemonic = 'illness spike retreat truth genius clock brain pass fit cave bargain toe'; - - // Mnemonic to match trezor-python test suite - // GAK5MSF74TJW6GLM7NLTL76YZJKM2S4CGP3UH4REJHPHZ4YBZW2GSBPW - // SDE2YU4V2IYSJIUH7MONDYZTSSLDXV5QDEGUUOLCU4TK7CZWTAXZ5CEG - $this->mnemonic = 'alcohol woman abuse must during monitor noble actual mixed trade anger aisle'; - - - $this->privateKeySigner = new PrivateKeySigner(Keypair::newFromMnemonic($this->mnemonic)); - } - - public function setUp() +mnemonic = 'illness spike retreat truth genius clock brain pass fit cave bargain toe'; + + // Mnemonic to match trezor-python test suite + // GAK5MSF74TJW6GLM7NLTL76YZJKM2S4CGP3UH4REJHPHZ4YBZW2GSBPW + // SDE2YU4V2IYSJIUH7MONDYZTSSLDXV5QDEGUUOLCU4TK7CZWTAXZ5CEG + $this->mnemonic = 'alcohol woman abuse must during monitor noble actual mixed trade anger aisle'; + + + $this->privateKeySigner = new PrivateKeySigner(Keypair::newFromMnemonic($this->mnemonic)); + } + + protected function setUp(): void { parent::setUp(); - - $signingProvider = getenv('STELLAR_SIGNING_PROVIDER'); - if (!$signingProvider) { - printf('STELLAR_SIGNING_PROVIDER must be defined' . PHP_EOL); - printf('For example: ' . PHP_EOL); - printf('export STELLAR_SIGNING_PROVIDER=trezor' . PHP_EOL); - die(); - } - - if ($signingProvider == 'trezor') { - $signer = new TrezorSigner(); - $trezorBinPath = getenv('TREZOR_BIN_PATH'); - if ($trezorBinPath) { - $signer->setTrezorBinPath($trezorBinPath); - } - - // Set the public key of the signer to the default to prevent - // unnecessary calls to the hardware wallet to retrieve the public key - $signer->setPublicKey(Keypair::newFromMnemonic($this->mnemonic)); - - $this->horizonServer->setSigningProvider($signer); - } - else { - die('Unsupported STELLAR_SIGNING_PROVIDER'); - } - } - - /** - * Immediately writes output so the tester can verify the correct information - * is displayed on the hardware wallet - * - * @param $message - */ - public function manualVerificationOutput($message) - { - print PHP_EOL . $message . PHP_EOL; - - ob_flush(); - } -} \ No newline at end of file + + $signingProvider = getenv('STELLAR_SIGNING_PROVIDER'); + if (!$signingProvider) { + printf('STELLAR_SIGNING_PROVIDER must be defined' . PHP_EOL); + printf('For example: ' . PHP_EOL); + printf('export STELLAR_SIGNING_PROVIDER=trezor' . PHP_EOL); + die(); + } + + if ($signingProvider == 'trezor') { + $signer = new TrezorSigner(); + $trezorBinPath = getenv('TREZOR_BIN_PATH'); + if ($trezorBinPath) { + $signer->setTrezorBinPath($trezorBinPath); + } + + // Set the public key of the signer to the default to prevent + // unnecessary calls to the hardware wallet to retrieve the public key + $signer->setPublicKey(Keypair::newFromMnemonic($this->mnemonic)); + + $this->horizonServer->setSigningProvider($signer); + } + else { + die('Unsupported STELLAR_SIGNING_PROVIDER'); + } + } + + /** + * Immediately writes output so the tester can verify the correct information + * is displayed on the hardware wallet + * + * @param $message + */ + public function manualVerificationOutput($message) + { + print PHP_EOL . $message . PHP_EOL; + + ob_flush(); + } +} diff --git a/tests/Util/IntegrationTest.php b/tests/Util/IntegrationTest.php index 43a65ca..978ec0c 100644 --- a/tests/Util/IntegrationTest.php +++ b/tests/Util/IntegrationTest.php @@ -1,125 +1,158 @@ -horizonBaseUrl = getenv('STELLAR_HORIZON_BASE_URL'); if (!$this->horizonBaseUrl) { - throw new \InvalidArgumentException('Environment variable STELLAR_HORIZON_BASE_URL must be defined'); + $this->markTestSkipped('STELLAR_HORIZON_BASE_URL is not set; skipping integration tests.'); } - + // Public : Public Global Stellar Network ; September 2015 // Testnet: Test SDF Network ; September 2015 - $this->networkPassword = getenv('STELLAR_NETWORK_PASSWORD'); + $this->networkPassword = getenv('STELLAR_NETWORK_PASSPHRASE'); if (!$this->networkPassword) { $this->networkPassword = 'Integration Test Network ; zulucrypto'; } - - $this->fixtureAccounts = $this->getFixtureAccounts(); - $this->fixtureAssets = $this->getFixtureAssets(); - + + $this->fixtureAccounts = $this->getFixtureAccounts(); + $this->fixtureAssets = $this->getFixtureAssets(); + $this->horizonServer = Server::customNet($this->horizonBaseUrl, $this->networkPassword); - } - - /** - * @return Keypair - * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException - */ - protected function getRandomFundedKeypair() - { - $keypair = Keypair::newFromRandom(); - $this->horizonServer->fundAccount($keypair); - return $keypair; + // Ensure core fixture accounts exist and are funded (friendbot) + foreach (['basic1', 'basic2', 'basic3'] as $name) { + if (!isset($this->fixtureAccounts[$name])) { + continue; + } + $this->ensureAccountExists($this->fixtureAccounts[$name]); + } } - - /** - * These are defined by the docker container, see: https://github.com/zulucrypto/docker-stellar-integration-test-network - */ - protected function getFixtureAccounts() + + /** + * @return Keypair + * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException + */ + protected function getRandomFundedKeypair() + { + $keypair = Keypair::newFromRandom(); + $this->horizonServer->fundAccount($keypair); + + return $keypair; + } + + /** + * These are defined by the docker container, see: https://github.com/zulucrypto/docker-stellar-integration-test-network + */ + protected function getFixtureAccounts() + { + return [ + // GAJCCCRIRXAYEU2ATNQAFYH4E2HKLN2LCKM2VPXCTJKIBVTRSOLEGCJZ + 'basic1' => Keypair::newFromSeed('SDJCZISO5M5XAUV6Y7MZJNN3JZ5BWPXDHV4GXP3MYNACVDNQRQSERXBC'), + // GCP6IHMHWRCF5TQ4ZP6TVIRNDZD56W42F42VHYWMVDGDAND75YGAHHBQ + 'basic2' => Keypair::newFromSeed('SCEDMZ7DUEOUGRQWEXHXEXISQ2NAWI5IDXRHYWT2FHTYLIQOSUK5FX2E'), + // GAPSWEVEZVAOTW6AJM26NIVBITCKXNOMGBZAOPFTFDTJGKYCIIPVI4RJ + 'basic3' => Keypair::newFromSeed('SBY7ZNSKQ3CDHH34RUWVIUCMM7UEWWFTCM6ORFT5QTE77JGDFCBGXSU5'), + + // GDJ7OPOMTHEUFEBT6VUR7ANXR6BOHKR754CZ3KMSIMQC43HHBEDVDWVG + 'usdIssuingKeypair' => Keypair::newFromSeed('SBJXZEVYRX244HKDY6L5JZYPWDQW6D3WLEE3PTMQM4CSUKGE37J4AC3W'), + // GBTO25DHZJ43Z5UI3JDAUQMHKP3SVUKLLBSNN7TFR7MW3PCLPSW3SFQQ + 'usdBankKeypair' => Keypair::newFromSeed('SDJOXTS4TE3Q3HUIFQK5AQCTRML6HIOUQIXDLCEQHICOFHU5CQN6DBLS'), + + // GC5DIPGB56HFCAUTX27K3TENHB65VQ2RNH2DJ3KALEXJHR6STPICMC3Y + 'jpyIssuingKeypair' => Keypair::newFromSeed('SDLK77FFXNCSTLXD6HMVGVR24FAK2GF6KX47I2FYOLRBCKPOD6TRW7V6'), + // GAFT3ZRCVXDFJLTKNU3C2I3UGW6HVNI65FX7LTMYB5DQDPOM4H7XZAT6 + 'jpyBankKeypair' => Keypair::newFromSeed('SCJ7RMMMCOOBTC77J5STNKV5EDAQDXXXPSDAOP66MBIIYLJYT7WZK2UN'), + // GBMAHYE3L74AKS36LLF3AGQC55AL4AVZMVCCLJZXL32U2WDBMSEOZPQJ + 'jpyMerchantKeypair' => Keypair::newFromSeed('SAR6ZY7XFHBW5YYQGXSORBGIQH2AKSXQP3JPWPHEN3RSRTCMN6JBMYHS'), + + // GC5DIPGB56HFCAUTX27K3TENHB65VQ2RNH2DJ3KALEXJHR6STPICMC3Y + 'eurIssuingKeypair' => Keypair::newFromSeed('SAXU3ZUG3RGQLAQBBPDPHANM4UOO32D7IDLBA57JH3GXYQSJLKYHHMRM'), + // GAFT3ZRCVXDFJLTKNU3C2I3UGW6HVNI65FX7LTMYB5DQDPOM4H7XZAT6 + 'eurBankKeypair' => Keypair::newFromSeed('SAFSNJPNEBAQFPXNVOBPXOVLJMEGRBHPOPHGK565WKLJQ3U6QC4N5H3C'), + ]; + } + + /** + * Depends on getFixtureAccounts() + */ + protected function getFixtureAssets() { return [ - // GAJCCCRIRXAYEU2ATNQAFYH4E2HKLN2LCKM2VPXCTJKIBVTRSOLEGCJZ - 'basic1' => Keypair::newFromSeed('SDJCZISO5M5XAUV6Y7MZJNN3JZ5BWPXDHV4GXP3MYNACVDNQRQSERXBC'), - // GCP6IHMHWRCF5TQ4ZP6TVIRNDZD56W42F42VHYWMVDGDAND75YGAHHBQ - 'basic2' => Keypair::newFromSeed('SCEDMZ7DUEOUGRQWEXHXEXISQ2NAWI5IDXRHYWT2FHTYLIQOSUK5FX2E'), - // GAPSWEVEZVAOTW6AJM26NIVBITCKXNOMGBZAOPFTFDTJGKYCIIPVI4RJ - 'basic3' => Keypair::newFromSeed('SBY7ZNSKQ3CDHH34RUWVIUCMM7UEWWFTCM6ORFT5QTE77JGDFCBGXSU5'), - - // GDJ7OPOMTHEUFEBT6VUR7ANXR6BOHKR754CZ3KMSIMQC43HHBEDVDWVG - 'usdIssuingKeypair' => Keypair::newFromSeed('SBJXZEVYRX244HKDY6L5JZYPWDQW6D3WLEE3PTMQM4CSUKGE37J4AC3W'), - // GBTO25DHZJ43Z5UI3JDAUQMHKP3SVUKLLBSNN7TFR7MW3PCLPSW3SFQQ - 'usdBankKeypair' => Keypair::newFromSeed('SDJOXTS4TE3Q3HUIFQK5AQCTRML6HIOUQIXDLCEQHICOFHU5CQN6DBLS'), - - // GC5DIPGB56HFCAUTX27K3TENHB65VQ2RNH2DJ3KALEXJHR6STPICMC3Y - 'jpyIssuingKeypair' => Keypair::newFromSeed('SDLK77FFXNCSTLXD6HMVGVR24FAK2GF6KX47I2FYOLRBCKPOD6TRW7V6'), - // GAFT3ZRCVXDFJLTKNU3C2I3UGW6HVNI65FX7LTMYB5DQDPOM4H7XZAT6 - 'jpyBankKeypair' => Keypair::newFromSeed('SCJ7RMMMCOOBTC77J5STNKV5EDAQDXXXPSDAOP66MBIIYLJYT7WZK2UN'), - // GBMAHYE3L74AKS36LLF3AGQC55AL4AVZMVCCLJZXL32U2WDBMSEOZPQJ - 'jpyMerchantKeypair' => Keypair::newFromSeed('SAR6ZY7XFHBW5YYQGXSORBGIQH2AKSXQP3JPWPHEN3RSRTCMN6JBMYHS'), - - // GC5DIPGB56HFCAUTX27K3TENHB65VQ2RNH2DJ3KALEXJHR6STPICMC3Y - 'eurIssuingKeypair' => Keypair::newFromSeed('SAXU3ZUG3RGQLAQBBPDPHANM4UOO32D7IDLBA57JH3GXYQSJLKYHHMRM'), - // GAFT3ZRCVXDFJLTKNU3C2I3UGW6HVNI65FX7LTMYB5DQDPOM4H7XZAT6 - 'eurBankKeypair' => Keypair::newFromSeed('SAFSNJPNEBAQFPXNVOBPXOVLJMEGRBHPOPHGK565WKLJQ3U6QC4N5H3C'), + 'usd' => Asset::newCustomAsset('USDTEST', $this->fixtureAccounts['usdIssuingKeypair']->getPublicKey()), + 'jpy' => Asset::newCustomAsset('JPYTEST', $this->fixtureAccounts['jpyIssuingKeypair']->getPublicKey()), + 'eur' => Asset::newCustomAsset('EURTEST', $this->fixtureAccounts['eurIssuingKeypair']->getPublicKey()), ]; } /** - * Depends on getFixtureAccounts() + * Ensure an account exists; if not, fund via friendbot and wait briefly. + * + * @param Keypair $keypair */ - protected function getFixtureAssets() + protected function ensureAccountExists(Keypair $keypair) { - return [ - 'usd' => Asset::newCustomAsset('USDTEST', $this->fixtureAccounts['usdIssuingKeypair']->getPublicKey()), - 'jpy' => Asset::newCustomAsset('JPYTEST', $this->fixtureAccounts['jpyIssuingKeypair']->getPublicKey()), - 'eur' => Asset::newCustomAsset('EURTEST', $this->fixtureAccounts['eurIssuingKeypair']->getPublicKey()), - ]; + $account = $this->horizonServer->getAccount($keypair); + if ($account) { + return; + } + + // Attempt to fund; friendbot returns 200 on success + $this->horizonServer->fundAccount($keypair); + + // Poll a few times until horizon ingests the account + for ($i = 0; $i < 5; $i++) { + usleep(200000); // 200ms + $account = $this->horizonServer->getAccount($keypair); + if ($account) { + return; + } + } } -} \ No newline at end of file +} diff --git a/tests/integration/AccountMergeOpTest.php b/tests/integration/AccountMergeOpTest.php index 22cced0..de669e8 100644 --- a/tests/integration/AccountMergeOpTest.php +++ b/tests/integration/AccountMergeOpTest.php @@ -1,37 +1,37 @@ -getRandomFundedKeypair(); - $mergeTo = $this->getRandomFundedKeypair(); - - - $this->horizonServer->buildTransaction($mergeFrom) - ->addMergeOperation($mergeTo) - ->submit($mergeFrom); - - // Verify mergeFrom account no longer exists - $mergeFromAccount = $this->horizonServer->getAccount($mergeFrom); - $this->assertNull($mergeFromAccount); - - $mergeToAccountBalance = $this->horizonServer - ->getAccount($mergeTo) - ->getNativeBalance(); - - // Verify mergeToAccount has double balance (minus fees) - $this->assertEquals(19999.99999, $mergeToAccountBalance); - } +getRandomFundedKeypair(); + $mergeTo = $this->getRandomFundedKeypair(); + + + $this->horizonServer->buildTransaction($mergeFrom) + ->addMergeOperation($mergeTo) + ->submit($mergeFrom); + + // Verify mergeFrom account no longer exists + $mergeFromAccount = $this->horizonServer->getAccount($mergeFrom); + $this->assertNull($mergeFromAccount); + + $mergeToAccountBalance = $this->horizonServer + ->getAccount($mergeTo) + ->getNativeBalance(); + + // Verify mergeToAccount has double balance (minus fees) + $this->assertEquals(19999.99999, $mergeToAccountBalance); + } } \ No newline at end of file diff --git a/tests/integration/AccountTest.php b/tests/integration/AccountTest.php index 3638ba3..7877d0b 100644 --- a/tests/integration/AccountTest.php +++ b/tests/integration/AccountTest.php @@ -1,69 +1,84 @@ -horizonServer->getAccount($this->fixtureAccounts['basic1']->getPublicKey()); - - $destinationAccountBefore = $this->horizonServer->getAccount($this->fixtureAccounts['basic2']->getPublicKey()); - - // Send a payment to basic2 - $response = $sourceAccount->sendNativeAsset( - // Send to basic2 account - $this->fixtureAccounts['basic2']->getPublicKey(), - $paymentAmount, - // Sign with basic1 seed - $this->fixtureAccounts['basic1']->getSecret() - ); - - $destinationAccountAfter = $this->horizonServer->getAccount($this->fixtureAccounts['basic2']->getPublicKey()); - - // Must be a valid hash - $this->assertNotEmpty($response->mustGetField('hash')); - - // Balance should have gone up by the paymentAmount - $this->assertEquals($destinationAccountBefore->getNativeBalance() + $paymentAmount, $destinationAccountAfter->getNativeBalance()); - } - - /** - * @group requires-integrationnet - */ - public function testGetPayments() - { - // Create a new account to receive the payments and fund via friendbot - $paymentDestKeypair = $this->getRandomFundedKeypair(); - - // Create a payment from a regular account - $payingKeypair = $this->fixtureAccounts['basic1']; - $payingAccount = $this->horizonServer->getAccount($payingKeypair->getPublicKey()); - $payingAccount->sendNativeAsset($paymentDestKeypair, 100, $payingKeypair); - - // Merge an account into the destination account - $mergingKeypair = $this->getRandomFundedKeypair(); - $this->horizonServer->buildTransaction($mergingKeypair) - ->addMergeOperation($paymentDestKeypair) - ->submit($mergingKeypair); - - // loading this too fast will miss the last payment - sleep(1); - $account = $this->horizonServer->getAccount($paymentDestKeypair->getPublicKey()); - - $this->assertCount(2, $account->getPayments()); - } -} \ No newline at end of file +horizonServer->getAccount($this->fixtureAccounts['basic1']->getPublicKey()); + + $destinationAccountBefore = $this->horizonServer->getAccount($this->fixtureAccounts['basic2']->getPublicKey()); + + // Send a payment to basic2 + $response = $sourceAccount->sendNativeAsset( + // Send to basic2 account + $this->fixtureAccounts['basic2']->getPublicKey(), + $paymentAmount, + // Sign with basic1 seed + $this->fixtureAccounts['basic1']->getSecret() + ); + + $destinationAccountAfter = $this->horizonServer->getAccount($this->fixtureAccounts['basic2']->getPublicKey()); + + // Must be a valid hash + $this->assertNotEmpty($response->mustGetField('hash')); + + // Balance should have gone up by the paymentAmount + $this->assertEquals($destinationAccountBefore->getNativeBalance() + $paymentAmount, $destinationAccountAfter->getNativeBalance()); + } + + /** + * @group requires-integrationnet + */ + public function testGetPayments() + { + // Create a new account to receive the payments and fund via friendbot + $paymentDestKeypair = $this->getRandomFundedKeypair(); + // Baseline: capture current mixed payments feed (will include create_account from friendbot) + $baselineAccount = $this->horizonServer->getAccount($paymentDestKeypair->getPublicKey()); + $baselineCount = count($baselineAccount->getPayments()); + // Create a payment from a regular account + $payingKeypair = $this->fixtureAccounts['basic1']; + $payingAccount = $this->horizonServer->getAccount($payingKeypair->getPublicKey()); + $payingAccount->sendNativeAsset($paymentDestKeypair, 100, $payingKeypair); + + // Merge an account into the destination account + $mergingKeypair = $this->getRandomFundedKeypair(); + $this->horizonServer->buildTransaction($mergingKeypair) + ->addMergeOperation($paymentDestKeypair) + ->submit($mergingKeypair); + + // Loading this too fast will miss the last payment + sleep(1); + $account = $this->horizonServer->getAccount($paymentDestKeypair->getPublicKey()); + + // In the unfiltered payments feed, we should see both the payment and the account merge + $allPayments = $account->getPayments(); + + $types = array_map(function($op) { return $op->getAssetTransferType(); }, $allPayments); + $this->assertContains('payment', $types); + $this->assertContains('account_merge', $types); + + // Assert we added exactly two new records to the unfiltered payments feed: + // - one payment + // - one account_merge + $this->assertCount($baselineCount + 2, $allPayments); + + // We expect exactly 1 payment-like operation: the direct payment (account_merge is excluded) + $this->assertCount(1, $account->getPaymentOperations()); + } +} diff --git a/tests/integration/ChangeTrustOpTest.php b/tests/integration/ChangeTrustOpTest.php index e4ad9ea..68cebe5 100644 --- a/tests/integration/ChangeTrustOpTest.php +++ b/tests/integration/ChangeTrustOpTest.php @@ -1,42 +1,42 @@ -getRandomFundedKeypair(); - $usdAsset = $this->fixtureAssets['usd']; - - $this->horizonServer->buildTransaction($keypair) - ->addChangeTrustOp($usdAsset, 4294967297)// 2^32 + 1 - ->submit($keypair); - - // Verify trustline is added - $account = $this->horizonServer->getAccount($keypair); - - $balanceAmount = $account->getCustomAssetBalance($usdAsset); - - $this->assertEquals(4294967297, $balanceAmount->getLimit()->getScaledValue()); - - // Remove trustline by setting to 0 - $this->horizonServer->buildTransaction($keypair) - ->addChangeTrustOp($usdAsset, 0) - ->submit($keypair); - - $account = $this->horizonServer->getAccount($keypair); - $balanceAmount = $account->getCustomAssetBalance($usdAsset); - // Should now be null - $this->assertNull($balanceAmount); - } +getRandomFundedKeypair(); + $usdAsset = $this->fixtureAssets['usd']; + + $this->horizonServer->buildTransaction($keypair) + ->addChangeTrustOp($usdAsset, 4294967297)// 2^32 + 1 + ->submit($keypair); + + // Verify trustline is added + $account = $this->horizonServer->getAccount($keypair); + + $balanceAmount = $account->getCustomAssetBalance($usdAsset); + + $this->assertEquals(4294967297, $balanceAmount->getLimit()->getScaledValue()); + + // Remove trustline by setting to 0 + $this->horizonServer->buildTransaction($keypair) + ->addChangeTrustOp($usdAsset, 0) + ->submit($keypair); + + $account = $this->horizonServer->getAccount($keypair); + $balanceAmount = $account->getCustomAssetBalance($usdAsset); + // Should now be null + $this->assertNull($balanceAmount); + } } \ No newline at end of file diff --git a/tests/integration/CreateAccountOpTest.php b/tests/integration/CreateAccountOpTest.php index 4b36d4e..f9c6f19 100644 --- a/tests/integration/CreateAccountOpTest.php +++ b/tests/integration/CreateAccountOpTest.php @@ -1,31 +1,32 @@ -fixtureAccounts['basic1']; - - $newKeypair = Keypair::newFromRandom(); - - $this->horizonServer->buildTransaction($sourceKeypair->getPublicKey()) - ->addCreateAccountOp($newKeypair->getAccountId(), 100.0333) - ->submit($sourceKeypair->getSecret()); - +fixtureAccounts['basic1']; + + $newKeypair = Keypair::newFromRandom(); + + $this->horizonServer->buildTransaction($sourceKeypair->getPublicKey()) + ->addCreateAccountOp($newKeypair->getAccountId(), 100.0333) + ->submit($sourceKeypair->getSecret()); + // Should then be able to retrieve the account and verify the balance $newAccount = $this->horizonServer->getAccount($newKeypair->getPublicKey()); - $this->assertEquals("100.0333", $newAccount->getNativeBalance()); + // Balance strings are formatted to 7 decimal places by design + $this->assertEquals("100.0333000", $newAccount->getNativeBalance()); } -} \ No newline at end of file +} diff --git a/tests/integration/CreatePassiveOfferOpTest.php b/tests/integration/CreatePassiveOfferOpTest.php index 1df918a..79e858e 100644 --- a/tests/integration/CreatePassiveOfferOpTest.php +++ b/tests/integration/CreatePassiveOfferOpTest.php @@ -1,35 +1,36 @@ -fixtureAccounts['usdBankKeypair']; - $usdAsset = $this->fixtureAssets['usd']; - - // Sell 100 USDTEST for 0.0005 XLM - $xlmPrice = new Price(5, 10000); - $offerOp = new CreatePassiveOfferOp($usdAsset, Asset::newNativeAsset(), 100, $xlmPrice); - +fixtureAccounts['usdBankKeypair']; + $usdAsset = $this->fixtureAssets['usd']; + + // Sell 100 USDTEST for 0.0005 XLM + $xlmPrice = new Price(5, 10000); + $offerOp = new CreatePassiveOfferOp($usdAsset, Asset::newNativeAsset(), 100, $xlmPrice); + $response = $this->horizonServer->buildTransaction($usdBankKeypair) ->addOperation($offerOp) ->submit($usdBankKeypair); + $this->assertTrue($response->getResult()->succeeded()); // todo: add support for viewing offers on an account and verify here // todo: verify canceling an offer works correctly } -} \ No newline at end of file +} diff --git a/tests/integration/ManageOfferOpTest.php b/tests/integration/ManageOfferOpTest.php index 2981d55..c4d7a45 100644 --- a/tests/integration/ManageOfferOpTest.php +++ b/tests/integration/ManageOfferOpTest.php @@ -1,35 +1,36 @@ -fixtureAccounts['usdBankKeypair']; - $usdAsset = $this->fixtureAssets['usd']; - - // Sell 100 USDTEST for 0.02 XLM - $xlmPrice = new Price(2, 100); - $offerOp = new ManageOfferOp($usdAsset, Asset::newNativeAsset(), 100, $xlmPrice); - +fixtureAccounts['usdBankKeypair']; + $usdAsset = $this->fixtureAssets['usd']; + + // Sell 100 USDTEST for 0.02 XLM + $xlmPrice = new Price(2, 100); + $offerOp = new ManageOfferOp($usdAsset, Asset::newNativeAsset(), 100, $xlmPrice); + $response = $this->horizonServer->buildTransaction($usdBankKeypair) ->addOperation($offerOp) ->submit($usdBankKeypair); + $this->assertTrue($response->getResult()->succeeded()); // todo: add support for offers and verify here // todo: verify canceling an offer } -} \ No newline at end of file +} diff --git a/tests/integration/PathPaymentOpTest.php b/tests/integration/PathPaymentOpTest.php index 713cba2..204d00c 100644 --- a/tests/integration/PathPaymentOpTest.php +++ b/tests/integration/PathPaymentOpTest.php @@ -1,42 +1,42 @@ - JPY trades - * - * todo: integrate this with payment path discovery in Horizon - * - * @group requires-integrationnet - * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException - * @throws \ErrorException - */ - public function testSingleStepPathPayment() - { - /** @var Keypair $sourceKeypair */ - $sourceKeypair = $this->fixtureAccounts['basic1']; - $destinationKeypair = $this->fixtureAccounts['jpyMerchantKeypair']; - - $usdAsset = $this->fixtureAssets['usd']; - $jpyAsset = $this->fixtureAssets['jpy']; - - $pathPayment = new PathPaymentOp(Asset::newNativeAsset(), 200, $destinationKeypair, $jpyAsset, 500); - - $pathPayment->addPath($usdAsset); - + JPY trades + * + * todo: integrate this with payment path discovery in Horizon + * + * @group requires-integrationnet + * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException + * @throws \ErrorException + */ + public function testSingleStepPathPayment() + { + /** @var Keypair $sourceKeypair */ + $sourceKeypair = $this->fixtureAccounts['basic1']; + $destinationKeypair = $this->fixtureAccounts['jpyMerchantKeypair']; + + $usdAsset = $this->fixtureAssets['usd']; + $jpyAsset = $this->fixtureAssets['jpy']; + + $pathPayment = new PathPaymentOp(Asset::newNativeAsset(), 200, $destinationKeypair, $jpyAsset, 500); + + $pathPayment->addPath($usdAsset); + $envelope = $this->horizonServer->buildTransaction($sourceKeypair) ->addOperation($pathPayment) ->getTransactionEnvelope(); - + $this->assertNotNull($envelope); // todo: need additional fixtures to verify path payment } -} \ No newline at end of file +} diff --git a/tests/integration/PaymentOpTest.php b/tests/integration/PaymentOpTest.php index ac86407..eb59f0d 100644 --- a/tests/integration/PaymentOpTest.php +++ b/tests/integration/PaymentOpTest.php @@ -1,120 +1,120 @@ -fixtureAccounts['basic1']; - $destinationKeypair = $this->fixtureAccounts['basic2']; - - $prevBalance = $this->horizonServer - ->getAccount($destinationKeypair) - ->getNativeBalance(); - - $this->horizonServer->buildTransaction($sourceKeypair) - ->addLumenPayment($destinationKeypair, 10.0000001) - ->submit($sourceKeypair); - - // Get updated balance - $newBalance = $this->horizonServer - ->getAccount($destinationKeypair) - ->getNativeBalance(); - - $this->assertEquals($prevBalance + 10.0000001, $newBalance); - } - - /** - * NOTE: Due to how PHP uses floating point numbers, it is important to always - * work in stroops when adding or subtracting balances. - * - * See test for an example - * - * @group requires-integrationnet - * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException - * @throws \ErrorException - */ - public function testCustomAssetPayment() - { - // Floating point failure example: - /* - $oldBalance = 1.605; - $newBalance = 1.61; - - var_dump($oldBalance + 0.005); - var_dump($newBalance); - if ($oldBalance + 0.005 === $newBalance) { - print "Equal\n"; - } - else { - print "Not Equal\n"; - } - */ - // Output: - // float(1.61) - // float(1.61) - // Not Equal - - $usdIssuingKeypair = $this->fixtureAccounts['usdIssuingKeypair']; - $usdAsset = $this->fixtureAssets['usd']; - - $usdBankKeypair = $this->fixtureAccounts['usdBankKeypair']; - - // Transfer from the issuer to the bank - $prevBalance = $this->horizonServer - ->getAccount($usdBankKeypair) - ->getCustomAssetBalanceStroops($usdAsset); - - $this->horizonServer->buildTransaction($usdIssuingKeypair) - ->addCustomAssetPaymentOp($usdAsset, 10.005, $usdBankKeypair) - ->submit($usdIssuingKeypair); - - $newBalance = $this->horizonServer - ->getAccount($usdBankKeypair) - ->getCustomAssetBalanceStroops($usdAsset); - - $this->assertEquals($prevBalance + (10.005 * StellarAmount::STROOP_SCALE), $newBalance); - } - - /** - * @group requires-integrationnet - * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException - * @throws \ErrorException - */ - public function testLargestCustomAssetPayment() - { - $transferTo = $this->getRandomFundedKeypair(); - $usdIssuingKeypair = $this->fixtureAccounts['usdIssuingKeypair']; - $usdAsset = $this->fixtureAssets['usd']; - - // Add trustline for the maximum amount - $this->horizonServer->buildTransaction($transferTo) - ->addChangeTrustOp($usdAsset, StellarAmount::newMaximum()) - ->submit($transferTo); - - // Transfer maximum amount - $this->horizonServer->buildTransaction($usdIssuingKeypair) - ->addCustomAssetPaymentOp($usdAsset, new BigInteger('9223372036854775807'), $transferTo) - ->submit($usdIssuingKeypair); - - $newBalance = $this->horizonServer - ->getAccount($transferTo) - ->getCustomAssetBalanceValue($usdAsset); - - $this->assertEquals(922337203685.4775807, $newBalance); - } +fixtureAccounts['basic1']; + $destinationKeypair = $this->fixtureAccounts['basic2']; + + $prevBalance = $this->horizonServer + ->getAccount($destinationKeypair) + ->getNativeBalance(); + + $this->horizonServer->buildTransaction($sourceKeypair) + ->addLumenPayment($destinationKeypair, 10.0000001) + ->submit($sourceKeypair); + + // Get updated balance + $newBalance = $this->horizonServer + ->getAccount($destinationKeypair) + ->getNativeBalance(); + + $this->assertEquals($prevBalance + 10.0000001, $newBalance); + } + + /** + * NOTE: Due to how PHP uses floating point numbers, it is important to always + * work in stroops when adding or subtracting balances. + * + * See test for an example + * + * @group requires-integrationnet + * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException + * @throws \ErrorException + */ + public function testCustomAssetPayment() + { + // Floating point failure example: + /* + $oldBalance = 1.605; + $newBalance = 1.61; + + var_dump($oldBalance + 0.005); + var_dump($newBalance); + if ($oldBalance + 0.005 === $newBalance) { + print "Equal\n"; + } + else { + print "Not Equal\n"; + } + */ + // Output: + // float(1.61) + // float(1.61) + // Not Equal + + $usdIssuingKeypair = $this->fixtureAccounts['usdIssuingKeypair']; + $usdAsset = $this->fixtureAssets['usd']; + + $usdBankKeypair = $this->fixtureAccounts['usdBankKeypair']; + + // Transfer from the issuer to the bank + $prevBalance = $this->horizonServer + ->getAccount($usdBankKeypair) + ->getCustomAssetBalanceStroops($usdAsset); + + $this->horizonServer->buildTransaction($usdIssuingKeypair) + ->addCustomAssetPaymentOp($usdAsset, 10.005, $usdBankKeypair) + ->submit($usdIssuingKeypair); + + $newBalance = $this->horizonServer + ->getAccount($usdBankKeypair) + ->getCustomAssetBalanceStroops($usdAsset); + + $this->assertEquals($prevBalance + (10.005 * StellarAmount::STROOP_SCALE), $newBalance); + } + + /** + * @group requires-integrationnet + * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException + * @throws \ErrorException + */ + public function testLargestCustomAssetPayment() + { + $transferTo = $this->getRandomFundedKeypair(); + $usdIssuingKeypair = $this->fixtureAccounts['usdIssuingKeypair']; + $usdAsset = $this->fixtureAssets['usd']; + + // Add trustline for the maximum amount + $this->horizonServer->buildTransaction($transferTo) + ->addChangeTrustOp($usdAsset, StellarAmount::newMaximum()) + ->submit($transferTo); + + // Transfer maximum amount + $this->horizonServer->buildTransaction($usdIssuingKeypair) + ->addCustomAssetPaymentOp($usdAsset, new BigInteger('9223372036854775807'), $transferTo) + ->submit($usdIssuingKeypair); + + $newBalance = $this->horizonServer + ->getAccount($transferTo) + ->getCustomAssetBalanceValue($usdAsset); + + $this->assertEquals(922337203685.4775807, $newBalance); + } } \ No newline at end of file diff --git a/tests/integration/ServerTest.php b/tests/integration/ServerTest.php index a4e11ee..21b0964 100644 --- a/tests/integration/ServerTest.php +++ b/tests/integration/ServerTest.php @@ -1,26 +1,26 @@ -horizonBaseUrl, $this->networkPassword); - - // Verify one of the fixture accounts can be retrieved - $account = $server->getAccount($this->fixtureAccounts['basic1']->getPublicKey()); - - // Account should have at least one balance - $this->assertNotEmpty($account->getBalances()); - } +horizonBaseUrl, $this->networkPassword); + + // Verify one of the fixture accounts can be retrieved + $account = $server->getAccount($this->fixtureAccounts['basic1']->getPublicKey()); + + // Account should have at least one balance + $this->assertNotEmpty($account->getBalances()); + } } \ No newline at end of file diff --git a/tests/integration/TransactionBuilderTest.php b/tests/integration/TransactionBuilderTest.php index 025590f..d6a7da9 100644 --- a/tests/integration/TransactionBuilderTest.php +++ b/tests/integration/TransactionBuilderTest.php @@ -1,97 +1,97 @@ -fixtureAccounts['basic1']; - $destinationKeypair = $this->fixtureAccounts['basic2']; - - $response = $this->horizonServer->buildTransaction($sourceKeypair) - ->addLumenPayment($destinationKeypair, 3) - ->submit($sourceKeypair); - - // All operations should have succeeded - $result = $response->getResult(); - - $this->assertTrue($result->succeeded()); - $this->assertCount(1, $result->getOperationResults()); - } - - /** - * Helper method to extract OperationResult XDR for writing other tests / debugging - * - * @group requires-integrationnet - */ - public function testGetXdr() - { - $this->markTestSkipped('For debugging'); - - $sourceKeypair = $this->fixtureAccounts['basic1']; - $destinationKeypair = $this->fixtureAccounts['basic2']; - $usdIssuingKeypair = Keypair::newFromSeed('SBJXZEVYRX244HKDY6L5JZYPWDQW6D3WLEE3PTMQM4CSUKGE37J4AC3W'); - $usdBankKeypair = Keypair::newFromSeed('SDJOXTS4TE3Q3HUIFQK5AQCTRML6HIOUQIXDLCEQHICOFHU5CQN6DBLS'); - $authRequiredIssuingKeypair = Keypair::newFromSeed('SABFYGWPSP3EEJ2EURHQYAIRTNK3SVQPED5PWOHGCWKPZBSCWBV4QGKE'); - - $usdAsset = Asset::newCustomAsset('USDTEST', $usdIssuingKeypair->getPublicKey()); - $authRequiredAsset = Asset::newCustomAsset('AUTHREQ', $authRequiredIssuingKeypair->getPublicKey()); - - //$op = new ManageOfferOp($usdAsset, Asset::newNativeAsset(), 0, new Price(3, 1), 8); - - $op = new ManageDataOp('asdf', 'jkl'); - - $response = $this->horizonServer->buildTransaction($sourceKeypair) - ->addOperation($op) - ->submit($sourceKeypair); - - $rawData = $response->getRawData(); - $xdrB64 = $rawData['result_xdr']; - $xdr = base64_decode($xdrB64); - - $xdr = substr($xdr,8 + 4 + 4); - print "XDR: \n"; - print base64_encode($xdr); - } - - /** - * @group requires-integrationnet - */ - public function testFailedTransactionResultSingleOp() - { - $sourceKeypair = $this->fixtureAccounts['basic1']; - $destinationKeypair = $this->fixtureAccounts['basic2']; - - // This should fail since the source account doesn't have enough funds - try { - $response = $this->horizonServer->buildTransaction($sourceKeypair) - ->addLumenPayment($destinationKeypair, 99999) - ->submit($sourceKeypair); - - $this->fail('Exception was expected'); - } - catch (PostTransactionException $ex) { - $result = $ex->getResult(); - $opResults = $result->getOperationResults(); - $this->assertCount(1, $opResults); - $this->assertEquals('payment_underfunded', $opResults[0]->getErrorCode()); - } - } +fixtureAccounts['basic1']; + $destinationKeypair = $this->fixtureAccounts['basic2']; + + $response = $this->horizonServer->buildTransaction($sourceKeypair) + ->addLumenPayment($destinationKeypair, 3) + ->submit($sourceKeypair); + + // All operations should have succeeded + $result = $response->getResult(); + + $this->assertTrue($result->succeeded()); + $this->assertCount(1, $result->getOperationResults()); + } + + /** + * Helper method to extract OperationResult XDR for writing other tests / debugging + * + * @group requires-integrationnet + */ + public function testGetXdr() + { + $this->markTestSkipped('For debugging'); + + $sourceKeypair = $this->fixtureAccounts['basic1']; + $destinationKeypair = $this->fixtureAccounts['basic2']; + $usdIssuingKeypair = Keypair::newFromSeed('SBJXZEVYRX244HKDY6L5JZYPWDQW6D3WLEE3PTMQM4CSUKGE37J4AC3W'); + $usdBankKeypair = Keypair::newFromSeed('SDJOXTS4TE3Q3HUIFQK5AQCTRML6HIOUQIXDLCEQHICOFHU5CQN6DBLS'); + $authRequiredIssuingKeypair = Keypair::newFromSeed('SABFYGWPSP3EEJ2EURHQYAIRTNK3SVQPED5PWOHGCWKPZBSCWBV4QGKE'); + + $usdAsset = Asset::newCustomAsset('USDTEST', $usdIssuingKeypair->getPublicKey()); + $authRequiredAsset = Asset::newCustomAsset('AUTHREQ', $authRequiredIssuingKeypair->getPublicKey()); + + //$op = new ManageOfferOp($usdAsset, Asset::newNativeAsset(), 0, new Price(3, 1), 8); + + $op = new ManageDataOp('asdf', 'jkl'); + + $response = $this->horizonServer->buildTransaction($sourceKeypair) + ->addOperation($op) + ->submit($sourceKeypair); + + $rawData = $response->getRawData(); + $xdrB64 = $rawData['result_xdr']; + $xdr = base64_decode($xdrB64); + + $xdr = substr($xdr,8 + 4 + 4); + print "XDR: \n"; + print base64_encode($xdr); + } + + /** + * @group requires-integrationnet + */ + public function testFailedTransactionResultSingleOp() + { + $sourceKeypair = $this->fixtureAccounts['basic1']; + $destinationKeypair = $this->fixtureAccounts['basic2']; + + // This should fail since the source account doesn't have enough funds + try { + $response = $this->horizonServer->buildTransaction($sourceKeypair) + ->addLumenPayment($destinationKeypair, 99999) + ->submit($sourceKeypair); + + $this->fail('Exception was expected'); + } + catch (PostTransactionException $ex) { + $result = $ex->getResult(); + $opResults = $result->getOperationResults(); + $this->assertCount(1, $opResults); + $this->assertEquals('payment_underfunded', $opResults[0]->getErrorCode()); + } + } } \ No newline at end of file diff --git a/tests/phpunit.xml.dist b/tests/phpunit.xml.dist index 1d78766..446180b 100644 --- a/tests/phpunit.xml.dist +++ b/tests/phpunit.xml.dist @@ -1,17 +1,16 @@ - + diff --git a/tests/run-unit.sh b/tests/run-unit.sh index 8b09763..f7ab3a7 100755 --- a/tests/run-unit.sh +++ b/tests/run-unit.sh @@ -10,4 +10,4 @@ DIR="$( cd "$( dirname "$0" )" && pwd )" # Run relative to the tests/ directory cd "$DIR" -../vendor/bin/phpunit -c "$DIR" "$@" \ No newline at end of file +../vendor/bin/phpunit -c "$DIR" "$@" diff --git a/tests/setup-integration-network.php b/tests/setup-integration-network.php index 4bf2279..dde32f1 100644 --- a/tests/setup-integration-network.php +++ b/tests/setup-integration-network.php @@ -1,159 +1,159 @@ - Bob for 500 EURTEST: - * /paths?destination_account=GALOPAYIVBYBZX3JYUET67WWBDKOOSPYQ2437IKKZCPXXA4HHOKUZ5OA&source_account=GD4JRFLPF4AGYQTLCMZ7Q7DRLGQZQTGWOOKDUCNRVKG66G5ZVYYFT76M&destination_asset_type=credit_alphanum12&destination_asset_code=EURTEST&destination_asset_issuer=GBOCHOYXRJ7JSN22MLEUC6VPYYYWQBY77YEY2FUPJVUZNW2AMAIA5ISC&destination_amount=500 - * - */ - -require_once(__DIR__ . '/../vendor/autoload.php'); - - -use ZuluCrypto\StellarSdk\Keypair; -use ZuluCrypto\StellarSdk\XdrModel\Asset; -use ZuluCrypto\StellarSdk\Server; -use ZuluCrypto\StellarSdk\XdrModel\Operation\ManageOfferOp; -use ZuluCrypto\StellarSdk\XdrModel\Price; -use ZuluCrypto\StellarSdk\XdrModel\Operation\SetOptionsOp; - - -$horizonBaseUrl = getenv('STELLAR_HORIZON_BASE_URL'); -if (!$horizonBaseUrl) $horizonBaseUrl = 'http://localhost:8000/'; - + Bob for 500 EURTEST: + * /paths?destination_account=GALOPAYIVBYBZX3JYUET67WWBDKOOSPYQ2437IKKZCPXXA4HHOKUZ5OA&source_account=GD4JRFLPF4AGYQTLCMZ7Q7DRLGQZQTGWOOKDUCNRVKG66G5ZVYYFT76M&destination_asset_type=credit_alphanum12&destination_asset_code=EURTEST&destination_asset_issuer=GBOCHOYXRJ7JSN22MLEUC6VPYYYWQBY77YEY2FUPJVUZNW2AMAIA5ISC&destination_amount=500 + * + */ + +require_once(__DIR__ . '/../vendor/autoload.php'); + + +use ZuluCrypto\StellarSdk\Keypair; +use ZuluCrypto\StellarSdk\XdrModel\Asset; +use ZuluCrypto\StellarSdk\Server; +use ZuluCrypto\StellarSdk\XdrModel\Operation\ManageOfferOp; +use ZuluCrypto\StellarSdk\XdrModel\Price; +use ZuluCrypto\StellarSdk\XdrModel\Operation\SetOptionsOp; + + +$horizonBaseUrl = getenv('STELLAR_HORIZON_BASE_URL'); +if (!$horizonBaseUrl) $horizonBaseUrl = 'http://localhost:8000/'; + $networkPassphrase = getenv('STELLAR_NETWORK_PASSPHRASE'); if (!$networkPassphrase) $networkPassphrase = 'Integration Test Network ; zulucrypto'; - -$server = Server::customNet($horizonBaseUrl, $networkPassphrase); - -// ------------------------------------------------------------ -// Keypairs - -print "Setting up accounts...\n"; - -// GDJ7OPOMTHEUFEBT6VUR7ANXR6BOHKR754CZ3KMSIMQC43HHBEDVDWVG -$usdIssuingKeypair = setupKeypair('SBJXZEVYRX244HKDY6L5JZYPWDQW6D3WLEE3PTMQM4CSUKGE37J4AC3W'); -// GBOCHOYXRJ7JSN22MLEUC6VPYYYWQBY77YEY2FUPJVUZNW2AMAIA5ISC -$eurIssuingKeypair = setupKeypair('SAXU3ZUG3RGQLAQBBPDPHANM4UOO32D7IDLBA57JH3GXYQSJLKYHHMRM'); -// GC5DIPGB56HFCAUTX27K3TENHB65VQ2RNH2DJ3KALEXJHR6STPICMC3Y -$jpyIssuingKeypair = setupKeypair('SDLK77FFXNCSTLXD6HMVGVR24FAK2GF6KX47I2FYOLRBCKPOD6TRW7V6'); -// GAOM2624VSUBOGXTKS6ZVZZRXYUQTFNMUOGTVW6O5UT6JSV4T6F457DA -$authRequiredIssuingKeypair = setupKeypair('SABFYGWPSP3EEJ2EURHQYAIRTNK3SVQPED5PWOHGCWKPZBSCWBV4QGKE'); - -// GBTO25DHZJ43Z5UI3JDAUQMHKP3SVUKLLBSNN7TFR7MW3PCLPSW3SFQQ -$usdBankKeypair = setupKeypair('SDJOXTS4TE3Q3HUIFQK5AQCTRML6HIOUQIXDLCEQHICOFHU5CQN6DBLS'); -// GAU7MRC2T3SAY23F4VYQJNSJNM4S2GWVYBEKC7T2Z7EY5D5N7CBU4QSH -$eurBankKeypair = setupKeypair('SAFSNJPNEBAQFPXNVOBPXOVLJMEGRBHPOPHGK565WKLJQ3U6QC4N5H3C'); -// GAFT3ZRCVXDFJLTKNU3C2I3UGW6HVNI65FX7LTMYB5DQDPOM4H7XZAT6 -$jpyBankKeypair = setupKeypair('SCJ7RMMMCOOBTC77J5STNKV5EDAQDXXXPSDAOP66MBIIYLJYT7WZK2UN'); - -// GBMAHYE3L74AKS36LLF3AGQC55AL4AVZMVCCLJZXL32U2WDBMSEOZPQJ -$jpyMerchantKeypair = setupKeypair('SAR6ZY7XFHBW5YYQGXSORBGIQH2AKSXQP3JPWPHEN3RSRTCMN6JBMYHS'); - - -// GD4JRFLPF4AGYQTLCMZ7Q7DRLGQZQTGWOOKDUCNRVKG66G5ZVYYFT76M -$userAliceKeypair = setupKeypair('SAA2U5UFW65DW3MLVX734BUQIHAWANQNBLTFT47X2NVVBCN7X6QC5AOG'); -// GALOPAYIVBYBZX3JYUET67WWBDKOOSPYQ2437IKKZCPXXA4HHOKUZ5OA -$userBobKeypair = setupKeypair('SBFMSGMYTSAJMCNEJQPPO65BNL5HSUXYKY4HPE2RZWXBP7C745YKYIUC'); - -// Define test assets -$nativeAsset = Asset::newNativeAsset(); -$usdAsset = Asset::newCustomAsset('USDTEST', $usdIssuingKeypair->getPublicKey()); -$eurAsset = Asset::newCustomAsset('EURTEST', $eurIssuingKeypair->getPublicKey()); -$jpyAsset = Asset::newCustomAsset('JPYTEST', $jpyIssuingKeypair->getPublicKey()); -$authRequiredAsset = Asset::newCustomAsset('AUTHREQ', $authRequiredIssuingKeypair->getPublicKey()); - -// Configure assets -print "Configuring assets...\n"; - -$op = new SetOptionsOp(); -$op->setAuthRevocable(true); -$op->setAuthRequired(true); -$server->buildTransaction($authRequiredIssuingKeypair) - ->addOperation($op) - ->submit($authRequiredIssuingKeypair); - -// Establish trustlines for banks to assets -print "Establishing trustlines...\n"; -$server->buildTransaction($usdBankKeypair) - ->addChangeTrustOp($usdAsset) - ->submit($usdBankKeypair); - -$server->buildTransaction($eurBankKeypair) - ->addChangeTrustOp($eurAsset) - ->submit($eurBankKeypair); - -$server->buildTransaction($jpyBankKeypair) - ->addChangeTrustOp($jpyAsset) - ->submit($jpyBankKeypair); - -// For users -$server->buildTransaction($userAliceKeypair) - ->addChangeTrustOp($eurAsset) - ->submit($userAliceKeypair); - -$server->buildTransaction($userAliceKeypair) - ->addChangeTrustOp($authRequiredAsset) - ->submit($userAliceKeypair); -$server->buildTransaction($authRequiredIssuingKeypair) - ->authorizeTrustline($authRequiredAsset, $userAliceKeypair) - ->submit($authRequiredIssuingKeypair); - -$server->buildTransaction($userBobKeypair) - ->addChangeTrustOp($eurAsset) - ->submit($userBobKeypair); - -// Fund the bank accounts -print "Funding Anchor accounts...\n"; -$server->buildTransaction($usdIssuingKeypair) - ->addCustomAssetPaymentOp($usdAsset, 1000000, $usdBankKeypair) - ->submit($usdIssuingKeypair->getSecret()); - -$server->buildTransaction($eurIssuingKeypair) - ->addCustomAssetPaymentOp($eurAsset, 1000000, $eurBankKeypair) - ->submit($eurIssuingKeypair->getSecret()); - -$server->buildTransaction($jpyIssuingKeypair) - ->addCustomAssetPaymentOp($jpyAsset, 1000000, $jpyBankKeypair) - ->submit($jpyIssuingKeypair->getSecret()); - -// Anchors have standing offers for their assets -print "Submitting custom asset offers...\n"; -$server->buildTransaction($usdBankKeypair) - ->addOperation(new ManageOfferOp($usdAsset, $nativeAsset, 500000, new Price(100))) - ->submit($usdBankKeypair->getSecret()); - -$server->buildTransaction($eurBankKeypair) - ->addOperation(new ManageOfferOp($eurAsset, $nativeAsset, 500000, new Price(120))) - ->submit($eurBankKeypair->getSecret()); - -$server->buildTransaction($jpyBankKeypair) - ->addOperation(new ManageOfferOp($jpyAsset, $nativeAsset, 500000, new Price(40))) - ->submit($jpyBankKeypair->getSecret()); - - - -/** - * Funds $secretKey from friendbot - * - * @param $secretKey - * @return Keypair - * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException - */ -function setupKeypair($secretKey) -{ - global $server; - - $keypair = Keypair::newFromSeed($secretKey); - - $account = $server->getAccount($keypair); - - if (!$account) { - $server->fundAccount($keypair->getPublicKey()); - } - - return $keypair; -} + +$server = Server::customNet($horizonBaseUrl, $networkPassphrase); + +// ------------------------------------------------------------ +// Keypairs + +print "Setting up accounts...\n"; + +// GDJ7OPOMTHEUFEBT6VUR7ANXR6BOHKR754CZ3KMSIMQC43HHBEDVDWVG +$usdIssuingKeypair = setupKeypair('SBJXZEVYRX244HKDY6L5JZYPWDQW6D3WLEE3PTMQM4CSUKGE37J4AC3W'); +// GBOCHOYXRJ7JSN22MLEUC6VPYYYWQBY77YEY2FUPJVUZNW2AMAIA5ISC +$eurIssuingKeypair = setupKeypair('SAXU3ZUG3RGQLAQBBPDPHANM4UOO32D7IDLBA57JH3GXYQSJLKYHHMRM'); +// GC5DIPGB56HFCAUTX27K3TENHB65VQ2RNH2DJ3KALEXJHR6STPICMC3Y +$jpyIssuingKeypair = setupKeypair('SDLK77FFXNCSTLXD6HMVGVR24FAK2GF6KX47I2FYOLRBCKPOD6TRW7V6'); +// GAOM2624VSUBOGXTKS6ZVZZRXYUQTFNMUOGTVW6O5UT6JSV4T6F457DA +$authRequiredIssuingKeypair = setupKeypair('SABFYGWPSP3EEJ2EURHQYAIRTNK3SVQPED5PWOHGCWKPZBSCWBV4QGKE'); + +// GBTO25DHZJ43Z5UI3JDAUQMHKP3SVUKLLBSNN7TFR7MW3PCLPSW3SFQQ +$usdBankKeypair = setupKeypair('SDJOXTS4TE3Q3HUIFQK5AQCTRML6HIOUQIXDLCEQHICOFHU5CQN6DBLS'); +// GAU7MRC2T3SAY23F4VYQJNSJNM4S2GWVYBEKC7T2Z7EY5D5N7CBU4QSH +$eurBankKeypair = setupKeypair('SAFSNJPNEBAQFPXNVOBPXOVLJMEGRBHPOPHGK565WKLJQ3U6QC4N5H3C'); +// GAFT3ZRCVXDFJLTKNU3C2I3UGW6HVNI65FX7LTMYB5DQDPOM4H7XZAT6 +$jpyBankKeypair = setupKeypair('SCJ7RMMMCOOBTC77J5STNKV5EDAQDXXXPSDAOP66MBIIYLJYT7WZK2UN'); + +// GBMAHYE3L74AKS36LLF3AGQC55AL4AVZMVCCLJZXL32U2WDBMSEOZPQJ +$jpyMerchantKeypair = setupKeypair('SAR6ZY7XFHBW5YYQGXSORBGIQH2AKSXQP3JPWPHEN3RSRTCMN6JBMYHS'); + + +// GD4JRFLPF4AGYQTLCMZ7Q7DRLGQZQTGWOOKDUCNRVKG66G5ZVYYFT76M +$userAliceKeypair = setupKeypair('SAA2U5UFW65DW3MLVX734BUQIHAWANQNBLTFT47X2NVVBCN7X6QC5AOG'); +// GALOPAYIVBYBZX3JYUET67WWBDKOOSPYQ2437IKKZCPXXA4HHOKUZ5OA +$userBobKeypair = setupKeypair('SBFMSGMYTSAJMCNEJQPPO65BNL5HSUXYKY4HPE2RZWXBP7C745YKYIUC'); + +// Define test assets +$nativeAsset = Asset::newNativeAsset(); +$usdAsset = Asset::newCustomAsset('USDTEST', $usdIssuingKeypair->getPublicKey()); +$eurAsset = Asset::newCustomAsset('EURTEST', $eurIssuingKeypair->getPublicKey()); +$jpyAsset = Asset::newCustomAsset('JPYTEST', $jpyIssuingKeypair->getPublicKey()); +$authRequiredAsset = Asset::newCustomAsset('AUTHREQ', $authRequiredIssuingKeypair->getPublicKey()); + +// Configure assets +print "Configuring assets...\n"; + +$op = new SetOptionsOp(); +$op->setAuthRevocable(true); +$op->setAuthRequired(true); +$server->buildTransaction($authRequiredIssuingKeypair) + ->addOperation($op) + ->submit($authRequiredIssuingKeypair); + +// Establish trustlines for banks to assets +print "Establishing trustlines...\n"; +$server->buildTransaction($usdBankKeypair) + ->addChangeTrustOp($usdAsset) + ->submit($usdBankKeypair); + +$server->buildTransaction($eurBankKeypair) + ->addChangeTrustOp($eurAsset) + ->submit($eurBankKeypair); + +$server->buildTransaction($jpyBankKeypair) + ->addChangeTrustOp($jpyAsset) + ->submit($jpyBankKeypair); + +// For users +$server->buildTransaction($userAliceKeypair) + ->addChangeTrustOp($eurAsset) + ->submit($userAliceKeypair); + +$server->buildTransaction($userAliceKeypair) + ->addChangeTrustOp($authRequiredAsset) + ->submit($userAliceKeypair); +$server->buildTransaction($authRequiredIssuingKeypair) + ->authorizeTrustline($authRequiredAsset, $userAliceKeypair) + ->submit($authRequiredIssuingKeypair); + +$server->buildTransaction($userBobKeypair) + ->addChangeTrustOp($eurAsset) + ->submit($userBobKeypair); + +// Fund the bank accounts +print "Funding Anchor accounts...\n"; +$server->buildTransaction($usdIssuingKeypair) + ->addCustomAssetPaymentOp($usdAsset, 1000000, $usdBankKeypair) + ->submit($usdIssuingKeypair->getSecret()); + +$server->buildTransaction($eurIssuingKeypair) + ->addCustomAssetPaymentOp($eurAsset, 1000000, $eurBankKeypair) + ->submit($eurIssuingKeypair->getSecret()); + +$server->buildTransaction($jpyIssuingKeypair) + ->addCustomAssetPaymentOp($jpyAsset, 1000000, $jpyBankKeypair) + ->submit($jpyIssuingKeypair->getSecret()); + +// Anchors have standing offers for their assets +print "Submitting custom asset offers...\n"; +$server->buildTransaction($usdBankKeypair) + ->addOperation(new ManageOfferOp($usdAsset, $nativeAsset, 500000, new Price(100))) + ->submit($usdBankKeypair->getSecret()); + +$server->buildTransaction($eurBankKeypair) + ->addOperation(new ManageOfferOp($eurAsset, $nativeAsset, 500000, new Price(120))) + ->submit($eurBankKeypair->getSecret()); + +$server->buildTransaction($jpyBankKeypair) + ->addOperation(new ManageOfferOp($jpyAsset, $nativeAsset, 500000, new Price(40))) + ->submit($jpyBankKeypair->getSecret()); + + + +/** + * Funds $secretKey from friendbot + * + * @param $secretKey + * @return Keypair + * @throws \ZuluCrypto\StellarSdk\Horizon\Exception\HorizonException + */ +function setupKeypair($secretKey) +{ + global $server; + + $keypair = Keypair::newFromSeed($secretKey); + + $account = $server->getAccount($keypair); + + if (!$account) { + $server->fundAccount($keypair->getPublicKey()); + } + + return $keypair; +}