fjffk简å�•的咖啡店科开å�‘2方法2 环æ»�皆山也。其西å�—诸峰,林壑尤美,望之蔚然而深秀者,ç�…ç�Šä¹Ÿã€‚山行六七里,æ¸�闻水声潺潺,而泻出于两峰之间者,酿泉也 ??????????????????????????????? ??????????????/????????????????? ............/................... .........................../... ??????????????????????????????? >>>>>>>>>>>>>/>>>>>>>>>>>>>>>>> ÿØÿà JFIF    ÿÛ „  ( %!1!%)+//.383,7(-.+  -%%-////---/-.+/--+------/------/--0+--/-/-----.-----ÿÀ  Â¥2" ÿÄ     ÿÄ J    ! 1AQ"aqÂ�2‘#BR‚¡Ã�Ñ3br’¢±Âð$CSƒ²á4c“%DsÓñÿÄ   ÿÄ *  !1AQa‘"2q3Â�±ð#b¡ÿÚ   ? ¼QxJQaÃ�uò¸Zö Úü8,Ã�Úú "SSn<rçù–´âE—^ªBÖ9À\†¸Â�ÔÂ�Ã�T­ÃÛ5 ëd´³Ã�#Ã�;Þ38ϔÂ� ¶H£M:wÃŽ3…³…âpÔF&‚FK¸9„â4àGEõªfÂ�ÿ ‘ñ(ßw­pŽF|È¥ù®häðÃ�Ѷ¹‘[Ã’inÙW¶ùñYËœQ{›K"išÒ[Ú8žë\F¹@-?v"ÔUâ€�,ìöžkÿ {I‡£šÃ�?e rÂ�íV ?> ......................................... ............................................................................. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>/>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> dsdfPK[$W]¹¿nÖŸŸLICENSEnu„[µü¤Copyright (c) 2011-2016 Mathias Verraes Copyright (c) 2016 Márk Sági-Kazár Copyright (c) 2016 Frederik Bosch 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. PK[$W]îy·f´´.readthedocs.ymlnu„[µü¤version: 2 build: os: "ubuntu-22.04" tools: python: "3" python: install: - requirements: doc/requirements.txt sphinx: configuration: doc/conf.py PK[$W]mNÒy\\ README.mdnu„[µü¤# Money [![Latest Version](https://img.shields.io/github/release/moneyphp/money.svg?style=flat-square)](https://github.com/moneyphp/money/releases) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/moneyphp/money/ci.yml?branch=master&style=flat-square) [![Total Downloads](https://img.shields.io/packagist/dt/moneyphp/money.svg?style=flat-square)](https://packagist.org/packages/moneyphp/money) [![Email](https://img.shields.io/badge/email-team@moneyphp.org-blue.svg?style=flat-square)](mailto:team@moneyphp.org) ![Money PHP](/resources/logo.png?raw=true) PHP library to make working with money safer, easier, and fun! > "If I had a dime for every time I've seen someone use FLOAT to store currency, I'd have $999.997634" -- [Bill Karwin](https://twitter.com/billkarwin/status/347561901460447232) In short: You shouldn't represent monetary values by a float Wherever you need to represent money, use this Money value object. Since version 3.0 this library uses [strings internally](https://github.com/moneyphp/money/pull/136) in order to support unlimited integers. ```php add($fiveEur); list($part1, $part2, $part3) = $tenEur->allocate([1, 1, 1]); assert($part1->equals(Money::EUR(334))); assert($part2->equals(Money::EUR(333))); assert($part3->equals(Money::EUR(333))); ``` The documentation is available at http://moneyphp.org ## Requirements This library requires the [BCMath PHP extension](https://www.php.net/manual/en/book.bc.php). There might be additional dependencies for specific feature, e.g. the Swap exchange implementation, check the documentation for more information. Version 4 requires PHP 8.0. For older version of PHP, use version 3 of this library. From version 4.5 this package will only support [PHP versions that actually receive updates by PHP itself](https://www.php.net/supported-versions.php). If you want to use the package with older PHP versions, you can of course use older versions of this package. ## Install Via Composer ```bash $ composer require moneyphp/money ``` ## Features - JSON Serialization - Big integer support utilizing different, transparent calculation logic upon availability (bcmath, gmp, plain php) - Money formatting (including intl formatter) - Currency repositories (ISO currencies included) - Money exchange (including [Swap](http://swap.voutzinos.org) implementation) ## Documentation Please see the [official documentation](http://moneyphp.org). ## Testing We try to follow TDD by using [phpunit](https://phpunit.de) to test this library. ```bash $ composer test ``` ### Running the tests in Docker Money requires a set of dependencies, so you might want to run it in Docker. First, build the image locally: ```bash $ docker build -t moneyphp . ``` Then run the tests: ```bash $ docker run --rm -it -v $PWD:/app -w /app moneyphp vendor/bin/phpunit --exclude-group segmentation ``` ## Contributing We would love to see you helping us to make this library better and better. Please keep in mind we do not use suffixes and prefixes in class names, so not `CurrenciesInterface`, but `Currencies`. Other than that, Style CI will help you using the same code style as we are using. Please provide tests when creating a PR and clear descriptions of bugs when filing issues. ## Security If you discover any security related issues, please contact us at [team@moneyphp.org](mailto:team@moneyphp.org). ## License The MIT License (MIT). Please see [License File](LICENSE) for more information. ## Acknowledgements This library is heavily inspired by [Martin Fowler's Money pattern](http://martinfowler.com/eaaCatalog/money.html). A special remark goes to [Mathias Verraes](https://github.com/mathiasverraes), without his contributions, in code and via his [blog](http://verraes.net/#blog), this library would not be where it stands now. PK[$W]û-õ' phpstan.neonnu„[µü¤parameters: level: 6 paths: - src - tests errorFormat: ticketswap editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' ignoreErrors: - identifier: staticMethod.alreadyNarrowedType path: tests/* - identifier: method.alreadyNarrowedType path: tests/* PK[$W]ݱ——’’src/Exception.phpnu„[µü¤ 1, 1 => 1, 2 => 1, 3 => 1, 4 => 1, 5 => 1, 6 => 1, 7 => 1, 8 => 1, 9 => 1]; /** * @phpstan-pure */ public function __construct(string $integerPart, string $fractionalPart = '') { if ($integerPart === '' && $fractionalPart === '') { throw new InvalidArgumentException('Empty number is invalid'); } $this->integerPart = self::parseIntegerPart($integerPart); $this->fractionalPart = self::parseFractionalPart($fractionalPart); } /** @phpstan-pure */ public static function fromString(string $number): self { $portions = explode('.', $number, 2); return new self( $portions[0], rtrim($portions[1] ?? '', '0') ); } /** @phpstan-pure */ public static function fromFloat(float $number): self { return self::fromString(sprintf('%.14F', $number)); } /** @phpstan-pure */ public static function fromNumber(int|string $number): self { if (is_int($number)) { return new self((string) $number); } return self::fromString($number); } /** * @phpstan-pure */ public function isDecimal(): bool { return $this->fractionalPart !== ''; } /** * @phpstan-pure */ public function isInteger(): bool { return $this->fractionalPart === ''; } /** * @phpstan-pure */ public function isHalf(): bool { return $this->fractionalPart === '5'; } /** * @phpstan-pure */ public function isCurrentEven(): bool { $lastIntegerPartNumber = (int) $this->integerPart[strlen($this->integerPart) - 1]; return $lastIntegerPartNumber % 2 === 0; } /** * @phpstan-pure */ public function isCloserToNext(): bool { if ($this->fractionalPart === '') { return false; } return $this->fractionalPart[0] >= 5; } /** * @phpstan-return numeric-string * * @phpstan-pure */ public function __toString(): string { if ($this->fractionalPart === '') { return $this->integerPart; } return $this->integerPart . '.' . $this->fractionalPart; } /** * @phpstan-pure */ public function isNegative(): bool { return $this->integerPart[0] === '-'; } /** * @phpstan-return numeric-string * * @phpstan-pure */ public function getIntegerPart(): string { return $this->integerPart; } /** * @phpstan-return numeric-string|'' * * @phpstan-pure */ public function getFractionalPart(): string { return $this->fractionalPart; } /** * @phpstan-return numeric-string * * @phpstan-pure */ public function getIntegerRoundingMultiplier(): string { if ($this->integerPart[0] === '-') { return '-1'; } return '1'; } public function base10(int $number): self { if ($this->integerPart === '0' && ! $this->fractionalPart) { return $this; } $sign = ''; $integerPart = $this->integerPart; if ($integerPart[0] === '-') { $sign = '-'; $integerPart = substr($integerPart, 1); } if ($number >= 0) { $integerPart = ltrim($integerPart, '0'); $lengthIntegerPart = strlen($integerPart); $integers = $lengthIntegerPart - min($number, $lengthIntegerPart); $zeroPad = $number - min($number, $lengthIntegerPart); return new self( $sign . substr($integerPart, 0, $integers), rtrim(str_pad('', $zeroPad, '0') . substr($integerPart, $integers) . $this->fractionalPart, '0') ); } $number = abs($number); $lengthFractionalPart = strlen($this->fractionalPart); $fractions = $lengthFractionalPart - min($number, $lengthFractionalPart); $zeroPad = $number - min($number, $lengthFractionalPart); return new self( $sign . ltrim($integerPart . substr($this->fractionalPart, 0, $lengthFractionalPart - $fractions) . str_pad('', $zeroPad, '0'), '0'), substr($this->fractionalPart, $lengthFractionalPart - $fractions) ); } /** * @phpstan-return numeric-string * * @phpstan-pure */ private static function parseIntegerPart(string $number): string { if ($number === '' || $number === '0') { return '0'; } if ($number === '-' || $number === '-0') { return '-0'; } // Happy path performance optimization: number can be used as-is if it is within // the platform's integer capabilities. if ($number === (string) (int) $number) { return $number; } $nonZero = false; for ($position = 0, $characters = strlen($number); $position < $characters; ++$position) { $digit = $number[$position]; if (! isset(self::NUMBERS[$digit]) && ! ($position === 0 && $digit === '-')) { throw new InvalidArgumentException(sprintf('Invalid integer part %1$s. Invalid digit %2$s found', $number, $digit)); } if ($digit === '-') { continue; } if ($nonZero === false && $digit === '0') { throw new InvalidArgumentException('Leading zeros are not allowed'); } $nonZero = true; } return $number; } /** * @phpstan-return numeric-string|'' * * @phpstan-pure */ private static function parseFractionalPart(string $number): string { if ($number === '') { return $number; } $intFraction = (int) $number; // Happy path performance optimization: number can be used as-is if it is within // the platform's integer capabilities, and it starts with zeroes only. if ($intFraction > 0 && ltrim($number, '0') === (string) $intFraction) { return $number; } for ($position = 0, $characters = strlen($number); $position < $characters; ++$position) { $digit = $number[$position]; if (! isset(self::NUMBERS[$digit])) { throw new InvalidArgumentException(sprintf('Invalid fractional part %1$s. Invalid digit %2$s found', $number, $digit)); } } return $number; } /** * @phpstan-pure */ public static function roundMoneyValue(string $moneyValue, int $targetDigits, int $havingDigits): string { $valueLength = strlen($moneyValue); $shouldRound = $targetDigits < $havingDigits && $valueLength - $havingDigits + $targetDigits > 0; if ($shouldRound && $moneyValue[$valueLength - $havingDigits + $targetDigits] >= 5) { $position = $valueLength - $havingDigits + $targetDigits; $addend = 1; while ($position > 0) { // @phpstan-ignore possiblyImpure.methodCall (no idea what it thinks this) $newValue = (string) ((int) $moneyValue[$position - 1] + $addend); if ($newValue >= 10) { $moneyValue[$position - 1] = $newValue[1]; $addend = $newValue[0]; --$position; if ($position === 0) { $moneyValue = $addend . $moneyValue; } } else { if ($moneyValue[$position - 1] === '-') { $moneyValue[$position - 1] = $newValue[0]; $moneyValue = '-' . $moneyValue; } else { $moneyValue[$position - 1] = $newValue[0]; } break; } } } return $moneyValue; } } PK[$W]J®Ë KƒKƒsrc/MoneyFactory.phpnu„[µü¤ * $fiveDollar = Money::USD(500); * * * @param non-empty-string $method * @param array{numeric-string|int} $arguments * * @throws InvalidArgumentException If amount is not integer(ish). * * @psalm-pure */ public static function __callStatic(string $method, array $arguments): Money { return new Money($arguments[0], new Currency($method)); } } PK[$W]ÂÝ´ž>ž> src/Money.phpnu„[µü¤ */ private static string $calculator = BcMathCalculator::class; /** * @param int|string $amount Amount, expressed in the smallest units of $currency (eg cents) * @phpstan-param int|numeric-string $amount * * @throws InvalidArgumentException If amount is not integer(ish). * * @phpstan-pure */ public function __construct(int|string $amount, private readonly Currency $currency) { if (filter_var($amount, FILTER_VALIDATE_INT) === false) { $numberFromString = Number::fromString((string) $amount); if (! $numberFromString->isInteger()) { throw new InvalidArgumentException('Amount must be an integer(ish) value'); } $this->amount = $numberFromString->getIntegerPart(); return; } $this->amount = (string) $amount; } /** * Checks whether a Money has the same Currency as this. */ public function isSameCurrency(Money ...$others): bool { foreach ($others as $other) { // Note: non-strict equality is intentional here, since `Currency` is `final` and reliable. if ($this->currency != $other->currency) { return false; } } return true; } /** * Checks whether the value represented by this object equals to the other. * * @phpstan-pure */ public function equals(Money $other): bool { // Note: non-strict equality is intentional here, since `Currency` is `final` and reliable. if ($this->currency != $other->currency) { return false; } if ($this->amount === $other->amount) { return true; } // @TODO do we want Money instance to be byte-equivalent when trailing zeroes exist? Very expensive! // Assumption: Money#equals() is called **less** than other number-based comparisons, and probably // only within test suites. Therefore, using complex normalization here is acceptable waste of performance. return $this->compare($other) === 0; } /** * Returns an integer less than, equal to, or greater than zero * if the value of this object is considered to be respectively * less than, equal to, or greater than the other. * * @phpstan-pure */ public function compare(Money $other): int { // Note: non-strict equality is intentional here, since `Currency` is `final` and reliable. if ($this->currency != $other->currency) { throw InvalidArgumentException::currencyMismatch(); } // @phpstan-ignore impure.staticPropertyAccess, possiblyImpure.methodCall return self::$calculator::compare($this->amount, $other->amount); } /** * Checks whether the value represented by this object is greater than the other. * * @phpstan-pure */ public function greaterThan(Money $other): bool { return $this->compare($other) > 0; } /** * @phpstan-pure */ public function greaterThanOrEqual(Money $other): bool { return $this->compare($other) >= 0; } /** * Checks whether the value represented by this object is less than the other. * * @phpstan-pure */ public function lessThan(Money $other): bool { return $this->compare($other) < 0; } /** * @phpstan-pure */ public function lessThanOrEqual(Money $other): bool { return $this->compare($other) <= 0; } /** * Returns the value represented by this object - amount, expressed in the smallest currency units (eg cents). * * @phpstan-return numeric-string */ public function getAmount(): string { return $this->amount; } /** * Returns the currency of this object. */ public function getCurrency(): Currency { return $this->currency; } /** * Returns a new Money object that represents * the sum of this and an other Money object. * * @phpstan-pure */ public function add(Money ...$addends): Money { $amount = $this->amount; foreach ($addends as $addend) { // Note: non-strict equality is intentional here, since `Currency` is `final` and reliable. if ($this->currency != $addend->currency) { throw InvalidArgumentException::currencyMismatch(); } // @phpstan-ignore impure.staticPropertyAccess, possiblyImpure.methodCall $amount = self::$calculator::add($amount, $addend->amount); } return new self($amount, $this->currency); } /** * Returns a new Money object that represents * the difference of this and an other Money object. * * @phpstan-pure */ public function subtract(Money ...$subtrahends): Money { $amount = $this->amount; foreach ($subtrahends as $subtrahend) { // Note: non-strict equality is intentional here, since `Currency` is `final` and reliable. if ($this->currency != $subtrahend->currency) { throw InvalidArgumentException::currencyMismatch(); } // @phpstan-ignore impure.staticPropertyAccess, possiblyImpure.methodCall $amount = self::$calculator::subtract($amount, $subtrahend->amount); } return new self($amount, $this->currency); } /** * Returns a new Money object that represents * the multiplied value by the given factor. * * @phpstan-param int|numeric-string $multiplier * @phpstan-param self::ROUND_* $roundingMode */ public function multiply(int|string $multiplier, int $roundingMode = self::ROUND_HALF_UP): Money { if (is_int($multiplier)) { $multiplier = (string) $multiplier; } $product = $this->round(self::$calculator::multiply($this->amount, $multiplier), $roundingMode); return new self($product, $this->currency); } /** * Returns a new Money object that represents * the divided value by the given factor. * * @phpstan-param int|numeric-string $divisor * @phpstan-param self::ROUND_* $roundingMode * * @phpstan-pure */ public function divide(int|string $divisor, int $roundingMode = self::ROUND_HALF_UP): Money { if (is_int($divisor)) { $divisor = (string) $divisor; } // @phpstan-ignore impure.staticPropertyAccess, possiblyImpure.methodCall $quotient = $this->round(self::$calculator::divide($this->amount, $divisor), $roundingMode); return new self($quotient, $this->currency); } /** * Returns a new Money object that represents * the remainder after dividing the value by * the given factor. */ public function mod(Money|int|string $divisor): Money { if ($divisor instanceof self) { // Note: non-strict equality is intentional here, since `Currency` is `final` and reliable. if ($this->currency != $divisor->currency) { throw InvalidArgumentException::currencyMismatch(); } $divisor = $divisor->amount; } else { $divisor = (string) Number::fromNumber($divisor); } return new self(self::$calculator::mod($this->amount, $divisor), $this->currency); } /** * Allocate the money according to a list of ratios. * * @phpstan-param TRatios $ratios * * @return Money[] * @phpstan-return ( * TRatios is list * ? non-empty-list * : non-empty-array * ) * * @template TRatios as non-empty-array */ public function allocate(array $ratios): array { $remainder = $this->amount; $results = []; $total = array_sum($ratios); if ($total <= 0) { throw new InvalidArgumentException('Cannot allocate to none, sum of ratios must be greater than zero'); } foreach ($ratios as $key => $ratio) { if ($ratio < 0) { throw new InvalidArgumentException('Cannot allocate to none, ratio must be zero or positive'); } $share = self::$calculator::share($this->amount, (string) $ratio, (string) $total); $results[$key] = new self($share, $this->currency); $remainder = self::$calculator::subtract($remainder, $share); } if (self::$calculator::compare($remainder, '0') === 0) { return $results; } $amount = $this->amount; $fractions = array_map(static function (float|int $ratio) use ($total, $amount) { $share = (float) $ratio / $total * (float) $amount; return $share - floor($share); }, $ratios); while (self::$calculator::compare($remainder, '0') > 0) { $index = $fractions !== [] ? array_keys($fractions, max($fractions))[0] : 0; $results[$index] = new self(self::$calculator::add($results[$index]->amount, '1'), $results[$index]->currency); $remainder = self::$calculator::subtract($remainder, '1'); unset($fractions[$index]); } return $results; } /** * Allocate the money among N targets. * * @phpstan-param positive-int $n * * @return Money[] * @phpstan-return non-empty-list * * @throws InvalidArgumentException If number of targets is not an integer. */ public function allocateTo(int $n): array { return $this->allocate(array_fill(0, $n, 1)); } /** * @phpstan-return numeric-string * * @throws InvalidArgumentException if the given $money is zero. */ public function ratioOf(Money $money): string { if ($money->isZero()) { throw new InvalidArgumentException('Cannot calculate a ratio of zero'); } // Note: non-strict equality is intentional here, since `Currency` is `final` and reliable. if ($this->currency != $money->currency) { throw InvalidArgumentException::currencyMismatch(); } return self::$calculator::divide($this->amount, $money->amount); } /** * @phpstan-param numeric-string $amount * @phpstan-param self::ROUND_* $roundingMode * * @phpstan-return numeric-string * * @phpstan-pure */ private function round(string $amount, int $roundingMode): string { if ($roundingMode === self::ROUND_UP) { // @phpstan-ignore impure.staticPropertyAccess, possiblyImpure.methodCall return self::$calculator::ceil($amount); } if ($roundingMode === self::ROUND_DOWN) { // @phpstan-ignore impure.staticPropertyAccess, possiblyImpure.methodCall return self::$calculator::floor($amount); } // @phpstan-ignore impure.staticPropertyAccess, possiblyImpure.methodCall return self::$calculator::round($amount, $roundingMode); } /** * Round to a specific unit. * * @phpstan-param non-negative-int $unit * @phpstan-param self::ROUND_* $roundingMode */ public function roundToUnit(int $unit, int $roundingMode = self::ROUND_HALF_UP): self { if ($unit === 0) { return $this; } $abs = self::$calculator::absolute($this->amount); if (strlen($abs) < $unit) { return new self('0', $this->currency); } $toBeRounded = substr($this->amount, 0, strlen($this->amount) - $unit) . '.' . substr($this->amount, $unit * -1); $result = $this->round($toBeRounded, $roundingMode); if ($result !== '0') { $result .= str_pad('', $unit, '0'); } return new self($result, $this->currency); } public function absolute(): Money { return new self( self::$calculator::absolute($this->amount), $this->currency ); } public function negative(): Money { return (new self(0, $this->currency)) ->subtract($this); } /** * Checks if the value represented by this object is zero. */ public function isZero(): bool { return self::$calculator::compare($this->amount, '0') === 0; } /** * Checks if the value represented by this object is positive. */ public function isPositive(): bool { return self::$calculator::compare($this->amount, '0') > 0; } /** * Checks if the value represented by this object is negative. */ public function isNegative(): bool { return self::$calculator::compare($this->amount, '0') < 0; } /** * {@inheritDoc} * * @phpstan-return array{amount: string, currency: string} */ public function jsonSerialize(): array { return [ 'amount' => $this->amount, 'currency' => $this->currency->jsonSerialize(), ]; } /** * @param Money $first * @param Money ...$collection * * @phpstan-pure */ public static function min(self $first, self ...$collection): Money { $min = $first; foreach ($collection as $money) { if (! $money->lessThan($min)) { continue; } $min = $money; } return $min; } /** * @param Money $first * @param Money ...$collection * * @phpstan-pure */ public static function max(self $first, self ...$collection): Money { $max = $first; foreach ($collection as $money) { if (! $money->greaterThan($max)) { continue; } $max = $money; } return $max; } /** @phpstan-pure */ public static function sum(self $first, self ...$collection): Money { return $first->add(...$collection); } /** @phpstan-pure */ public static function avg(self $first, self ...$collection): Money { return $first->add(...$collection)->divide((string) (count($collection) + 1)); } /** @phpstan-param class-string $calculator */ public static function registerCalculator(string $calculator): void { self::$calculator = $calculator; } /** @phpstan-return class-string */ public static function getCalculator(): string { return self::$calculator; } } PK[$W][Ãì src/CurrencyPair.phpnu„[µü¤counterCurrency; } /** * Returns the base currency. */ public function getBaseCurrency(): Currency { return $this->baseCurrency; } /** * Returns the conversion ratio. * * @phpstan-return numeric-string */ public function getConversionRatio(): string { return $this->conversionRatio; } /** * Checks if another CurrencyPair has the same parameters as this. */ public function equals(CurrencyPair $other): bool { return $this->baseCurrency->equals($other->baseCurrency) && $this->counterCurrency->equals($other->counterCurrency) && $this->conversionRatio === $other->conversionRatio; } /** * {@inheritDoc} * * @phpstan-return array{baseCurrency: Currency, counterCurrency: Currency, ratio: numeric-string} */ public function jsonSerialize(): array { return [ 'baseCurrency' => $this->baseCurrency, 'counterCurrency' => $this->counterCurrency, 'ratio' => $this->conversionRatio, ]; } } PK[$W]*¼ž{··!src/Parser/BitcoinMoneyParser.phpnu„[µü¤fractionDigits - 1) * -1, '0'); } else { $decimal .= str_pad('', $this->fractionDigits, '0'); } if (substr($decimal, 0, 1) === '-') { $decimal = '-' . ltrim(substr($decimal, 1), '0'); } else { $decimal = ltrim($decimal, '0'); } if ($decimal === '') { $decimal = '0'; } return new Money($decimal, $currency); } } PK[$W]5ÑbÉ5 5 src/Parser/IntlMoneyParser.phpnu„[µü¤formatter->parseCurrency($money, $currency); if ($decimal === false || $decimal === null) { throw new ParserException('Cannot parse ' . $money . ' to Money. ' . $this->formatter->getErrorMessage()); } if ($fallbackCurrency === null) { assert($currency !== ''); $fallbackCurrency = new Currency($currency); } $decimal = (string) $decimal; $subunit = $this->currencies->subunitFor($fallbackCurrency); $decimalPosition = strpos($decimal, '.'); if ($decimalPosition !== false) { $decimalLength = strlen($decimal); $fractionDigits = $decimalLength - $decimalPosition - 1; $decimal = str_replace('.', '', $decimal); $decimal = Number::roundMoneyValue($decimal, $subunit, $fractionDigits); if ($fractionDigits > $subunit) { $decimal = substr($decimal, 0, $decimalPosition + $subunit); } elseif ($fractionDigits < $subunit) { $decimal .= str_pad('', $subunit - $fractionDigits, '0'); } } else { $decimal .= str_pad('', $subunit, '0'); } if ($decimal[0] === '-') { $decimal = '-' . ltrim(substr($decimal, 1), '0'); } else { $decimal = ltrim($decimal, '0'); } if ($decimal === '') { $decimal = '0'; } return new Money($decimal, $fallbackCurrency); } } PK[$W],òi;¾)src/Parser/IntlLocalizedDecimalParser.phpnu„[µü¤formatter->parse($money); if ($decimal === false) { throw new ParserException('Cannot parse ' . $money . ' to Money. ' . $this->formatter->getErrorMessage()); } $decimal = (string) $decimal; $subunit = $this->currencies->subunitFor($fallbackCurrency); $decimalPosition = strpos($decimal, '.'); if ($decimalPosition !== false) { $decimalLength = strlen($decimal); $fractionDigits = $decimalLength - $decimalPosition - 1; $decimal = str_replace('.', '', $decimal); $decimal = Number::roundMoneyValue($decimal, $subunit, $fractionDigits); if ($fractionDigits > $subunit) { $decimal = substr($decimal, 0, $decimalPosition + $subunit); } elseif ($fractionDigits < $subunit) { $decimal .= str_pad('', $subunit - $fractionDigits, '0'); } } else { $decimal .= str_pad('', $subunit, '0'); } if ($decimal[0] === '-') { $decimal = '-' . ltrim(substr($decimal, 1), '0'); } else { $decimal = ltrim($decimal, '0'); } if ($decimal === '') { $decimal = '0'; } return new Money($decimal, $fallbackCurrency); } } PK[$W]dºÅûgg#src/Parser/AggregateMoneyParser.phpnu„[µü¤ $parsers */ public function __construct(private readonly array $parsers) { } public function parse(string $money, Currency|null $fallbackCurrency = null): Money { foreach ($this->parsers as $parser) { try { return $parser->parse($money, $fallbackCurrency); } catch (Exception\ParserException) { } } throw new Exception\ParserException(sprintf('Unable to parse %s', $money)); } } PK[$W]a‹ø_ _ !src/Parser/DecimalMoneyParser.phpnu„[µü¤-)?(?P\d+)?\.?(?P\d+)?$/'; public function __construct(private readonly Currencies $currencies) { } public function parse(string $money, Currency|null $fallbackCurrency = null): Money { if ($fallbackCurrency === null) { throw new ParserException('DecimalMoneyParser cannot parse currency symbols. Use fallbackCurrency argument'); } $decimal = trim($money); if ($decimal === '') { return new Money(0, $fallbackCurrency); } if (! preg_match(self::DECIMAL_PATTERN, $decimal, $matches) || ! isset($matches['digits'])) { throw new ParserException(sprintf('Cannot parse "%s" to Money.', $decimal)); } $negative = isset($matches['sign']) && $matches['sign'] === '-'; $decimal = $matches['digits']; if ($negative) { $decimal = '-' . $decimal; } $subunit = $this->currencies->subunitFor($fallbackCurrency); if (isset($matches['fraction'])) { $fractionDigits = strlen($matches['fraction']); $decimal .= $matches['fraction']; $decimal = Number::roundMoneyValue($decimal, $subunit, $fractionDigits); if ($fractionDigits > $subunit) { $decimal = substr($decimal, 0, $subunit - $fractionDigits); } elseif ($fractionDigits < $subunit) { $decimal .= str_pad('', $subunit - $fractionDigits, '0'); } } else { $decimal .= str_pad('', $subunit, '0'); } if ($negative) { $decimal = '-' . ltrim(substr($decimal, 1), '0'); } else { $decimal = ltrim($decimal, '0'); } if ($decimal === '' || $decimal === '-') { $decimal = '0'; } return new Money($decimal, $fallbackCurrency); } } PK[$W]k[Õöösrc/Exchange/SwapExchange.phpnu„[µü¤swap->latest($baseCurrency->getCode() . '/' . $counterCurrency->getCode()); } catch (ExchangerException) { throw UnresolvableCurrencyPairException::createFromCurrencies($baseCurrency, $counterCurrency); } $rateValue = sprintf('%.14F', $rate->getValue()); return new CurrencyPair($baseCurrency, $counterCurrency, $rateValue); } } PK[$W]´XJD55!src/Exchange/IndirectExchange.phpnu„[µü¤exchange->quote($baseCurrency, $counterCurrency); } catch (UnresolvableCurrencyPairException) { $rate = array_reduce( $this->getConversions($baseCurrency, $counterCurrency), /** * @phpstan-param numeric-string $carry * * @phpstan-return numeric-string */ static function (string $carry, CurrencyPair $pair) { $calculator = Money::getCalculator(); return $calculator::multiply($carry, $pair->getConversionRatio()); }, '1.0' ); return new CurrencyPair($baseCurrency, $counterCurrency, $rate); } } /** * @return CurrencyPair[] * * @throws UnresolvableCurrencyPairException */ private function getConversions(Currency $baseCurrency, Currency $counterCurrency): array { $startNode = new IndirectExchangeQueuedItem($baseCurrency); $startNode->discovered = true; /** @phpstan-var array $nodes */ $nodes = [$baseCurrency->getCode() => $startNode]; /** @psam-var SplQueue $frontier */ $frontier = new SplQueue(); $frontier->enqueue($startNode); while ($frontier->count()) { /** @phpstan-var IndirectExchangeQueuedItem $currentNode */ $currentNode = $frontier->dequeue(); $currentCurrency = $currentNode->currency; if ($currentCurrency->equals($counterCurrency)) { return $this->reconstructConversionChain($nodes, $currentNode); } foreach ($this->currencies as $candidateCurrency) { if (! isset($nodes[$candidateCurrency->getCode()])) { $nodes[$candidateCurrency->getCode()] = new IndirectExchangeQueuedItem($candidateCurrency); } $node = $nodes[$candidateCurrency->getCode()]; if ($node->discovered) { continue; } try { // Check if the candidate is a neighbor. This will throw an exception if it isn't. $this->exchange->quote($currentCurrency, $candidateCurrency); $node->discovered = true; $node->parent = $currentNode; $frontier->enqueue($node); } catch (UnresolvableCurrencyPairException) { // Not a neighbor. Move on. } } } throw UnresolvableCurrencyPairException::createFromCurrencies($baseCurrency, $counterCurrency); } /** * @phpstan-param array $currencies * * @return CurrencyPair[] * @phpstan-return list */ private function reconstructConversionChain(array $currencies, IndirectExchangeQueuedItem $goalNode): array { $current = $goalNode; $conversions = []; while ($current->parent) { $previous = $currencies[$current->parent->currency->getCode()]; $conversions[] = $this->exchange->quote($previous->currency, $current->currency); $current = $previous; } return array_reverse($conversions); } } PK[$W]WŠðPP+src/Exchange/IndirectExchangeQueuedItem.phpnu„[µü¤getCode(), $counterCurrency->getCode()) ); $rate = $this->exchanger->getExchangeRate($query); } catch (ExchangerException) { throw UnresolvableCurrencyPairException::createFromCurrencies($baseCurrency, $counterCurrency); } $rateValue = sprintf('%.14F', $rate->getValue()); return new CurrencyPair($baseCurrency, $counterCurrency, $rateValue); } } PK[$W]¶=z‚ØØsrc/Exchange/FixedExchange.phpnu„[µü¤> $list */ public function __construct(private readonly array $list) { } public function quote(Currency $baseCurrency, Currency $counterCurrency): CurrencyPair { if (isset($this->list[$baseCurrency->getCode()][$counterCurrency->getCode()])) { return new CurrencyPair( $baseCurrency, $counterCurrency, $this->list[$baseCurrency->getCode()][$counterCurrency->getCode()] ); } throw UnresolvableCurrencyPairException::createFromCurrencies($baseCurrency, $counterCurrency); } } PK[$W] Ý7Eææ+src/Exchange/ReversedCurrenciesExchange.phpnu„[µü¤exchange->quote($baseCurrency, $counterCurrency); } catch (UnresolvableCurrencyPairException $exception) { $calculator = Money::getCalculator(); try { $currencyPair = $this->exchange->quote($counterCurrency, $baseCurrency); return new CurrencyPair( $baseCurrency, $counterCurrency, $calculator::divide('1', $currencyPair->getConversionRatio()) ); } catch (UnresolvableCurrencyPairException) { throw $exception; } } } } PK[$W]‚ì&ûû!src/Exception/ParserException.phpnu„[µü¤getCode(), $counterCurrency->getCode() ); return new self($message); } } PK[$W]ìñÑn$src/Exception/FormatterException.phpnu„[µü¤getCurrency()->getCode() !== BitcoinCurrencies::CODE) { throw new FormatterException('Bitcoin Formatter can only format Bitcoin currency'); } $valueBase = $money->getAmount(); $negative = false; if ($valueBase[0] === '-') { $negative = true; $valueBase = substr($valueBase, 1); } $subunit = $this->currencies->subunitFor($money->getCurrency()); $valueBase = Number::roundMoneyValue($valueBase, $this->fractionDigits, $subunit); $valueLength = strlen($valueBase); if ($valueLength > $subunit) { $formatted = substr($valueBase, 0, $valueLength - $subunit); if ($subunit) { $formatted .= '.'; $formatted .= substr($valueBase, $valueLength - $subunit); } } else { $formatted = '0.' . str_pad('', $subunit - $valueLength, '0') . $valueBase; } if ($this->fractionDigits === 0) { $formatted = substr($formatted, 0, (int) strpos($formatted, '.')); } elseif ($this->fractionDigits > $subunit) { $formatted .= str_pad('', $this->fractionDigits - $subunit, '0'); } elseif ($this->fractionDigits < $subunit) { $lastDigit = (int) strpos($formatted, '.') + $this->fractionDigits + 1; $formatted = substr($formatted, 0, $lastDigit); } $formatted = BitcoinCurrencies::SYMBOL . $formatted; if ($negative) { $formatted = '-' . $formatted; } return $formatted; } } PK[$W]–=æÔjj'src/Formatter/DecimalMoneyFormatter.phpnu„[µü¤getAmount(); $negative = $valueBase[0] === '-'; if ($negative) { $valueBase = substr($valueBase, 1); } $subunit = $this->currencies->subunitFor($money->getCurrency()); $valueLength = strlen($valueBase); if ($valueLength > $subunit) { $formatted = substr($valueBase, 0, $valueLength - $subunit); $decimalDigits = substr($valueBase, $valueLength - $subunit); if (strlen($decimalDigits) > 0) { $formatted .= '.' . $decimalDigits; } } else { $formatted = '0.' . str_pad('', $subunit - $valueLength, '0') . $valueBase; } if ($negative) { $formatted = '-' . $formatted; } assert($formatted !== ''); return $formatted; } } PK[$W]ÿÚ“ââ$src/Formatter/IntlMoneyFormatter.phpnu„[µü¤getAmount(); $negative = $valueBase[0] === '-'; if ($negative) { $valueBase = substr($valueBase, 1); } $subunit = $this->currencies->subunitFor($money->getCurrency()); $valueLength = strlen($valueBase); if ($valueLength > $subunit) { $formatted = substr($valueBase, 0, $valueLength - $subunit); $decimalDigits = substr($valueBase, $valueLength - $subunit); if (strlen($decimalDigits) > 0) { $formatted .= '.' . $decimalDigits; } } else { $formatted = '0.' . str_pad('', $subunit - $valueLength, '0') . $valueBase; } if ($negative) { $formatted = '-' . $formatted; } $formatted = $this->formatter->formatCurrency((float) $formatted, $money->getCurrency()->getCode()); assert($formatted !== ''); return $formatted; } } PK[$W]ظ—œÎÎ)src/Formatter/AggregateMoneyFormatter.phpnu„[µü¤ indexed by currency code */ private array $formatters; /** * @param MoneyFormatter[] $formatters indexed by currency code * @phpstan-param non-empty-array $formatters indexed by currency code */ public function __construct(array $formatters) { $this->formatters = $formatters; } public function format(Money $money): string { $currencyCode = $money->getCurrency()->getCode(); if (isset($this->formatters[$currencyCode])) { return $this->formatters[$currencyCode]->format($money); } if (isset($this->formatters['*'])) { return $this->formatters['*']->format($money); } throw new FormatterException('No formatter found for currency ' . $currencyCode); } } PK[$W]˜K÷ôô/src/Formatter/IntlLocalizedDecimalFormatter.phpnu„[µü¤getAmount(); $negative = $valueBase[0] === '-'; if ($negative) { $valueBase = substr($valueBase, 1); } $subunit = $this->currencies->subunitFor($money->getCurrency()); $valueLength = strlen($valueBase); if ($valueLength > $subunit) { $formatted = substr($valueBase, 0, $valueLength - $subunit); $decimalDigits = substr($valueBase, $valueLength - $subunit); if (strlen($decimalDigits) > 0) { $formatted .= '.' . $decimalDigits; } } else { $formatted = '0.' . str_pad('', $subunit - $valueLength, '0') . $valueBase; } if ($negative) { $formatted = '-' . $formatted; } $formatted = $this->formatter->format((float) $formatted); assert(is_string($formatted) && $formatted !== ''); return $formatted; } } PK[$W]'hèɵ µ src/Converter.phpnu„[µü¤convertAgainstCurrencyPair( $money, $this->exchange->quote( $money->getCurrency(), $counterCurrency ), $roundingMode ); } /** * @param Money::ROUND_* $roundingMode * * @return array{0: Money, 1: CurrencyPair} */ public function convertAndReturnWithCurrencyPair(Money $money, Currency $counterCurrency, int $roundingMode = Money::ROUND_HALF_UP): array { $pair = $this->exchange->quote( $money->getCurrency(), $counterCurrency ); return [$this->convertAgainstCurrencyPair($money, $pair, $roundingMode), $pair]; } /** * @param Money::ROUND_* $roundingMode */ public function convertAgainstCurrencyPair(Money $money, CurrencyPair $currencyPair, int $roundingMode = Money::ROUND_HALF_UP): Money { if (! $money->getCurrency()->equals($currencyPair->getBaseCurrency())) { throw new InvalidArgumentException( sprintf( 'Expecting to convert against base currency %s, but got %s instead', $money->getCurrency()->getCode(), $currencyPair->getBaseCurrency()->getCode() ) ); } $ratio = $currencyPair->getConversionRatio(); $baseCurrencySubunit = $this->currencies->subunitFor($currencyPair->getBaseCurrency()); $counterCurrencySubunit = $this->currencies->subunitFor($currencyPair->getCounterCurrency()); $subunitDifference = $baseCurrencySubunit - $counterCurrencySubunit; $ratio = Number::fromString($ratio) ->base10($subunitDifference) ->__toString(); $counterValue = $money->multiply($ratio, $roundingMode); return new Money($counterValue->getAmount(), $currencyPair->getCounterCurrency()); } } PK[$W]ªÀ™YWWsrc/MoneyParser.phpnu„[µü¤ */ interface Currencies extends IteratorAggregate { /** * Checks whether a currency is available in the current context. */ public function contains(Currency $currency): bool; /** * Returns the subunit for a currency. * * @throws UnknownCurrencyException If currency is not available in the current context. */ public function subunitFor(Currency $currency): int; /** * @return Traversable */ public function getIterator(): Traversable; } PK[$W]Åm¶¢&¢& src/Calculator/GmpCalculator.phpnu„[µü¤isDecimal() || $bNum->isDecimal()) { $integersCompared = gmp_cmp($aNum->getIntegerPart(), $bNum->getIntegerPart()); if ($integersCompared !== 0) { return $integersCompared; } $aNumFractional = $aNum->getFractionalPart() === '' ? '0' : $aNum->getFractionalPart(); $bNumFractional = $bNum->getFractionalPart() === '' ? '0' : $bNum->getFractionalPart(); return gmp_cmp($aNumFractional, $bNumFractional); } return gmp_cmp($a, $b); } /** @phpstan-pure */ public static function add(string $amount, string $addend): string { return gmp_strval(gmp_add($amount, $addend)); } /** @phpstan-pure */ public static function subtract(string $amount, string $subtrahend): string { return gmp_strval(gmp_sub($amount, $subtrahend)); } /** @phpstan-pure */ public static function multiply(string $amount, string $multiplier): string { $multiplier = Number::fromString($multiplier); if ($multiplier->isDecimal()) { $decimalPlaces = strlen($multiplier->getFractionalPart()); $multiplierBase = $multiplier->getIntegerPart(); $negativeZero = $multiplierBase === '-0'; if ($negativeZero) { $multiplierBase = '-'; } if ($multiplierBase) { $multiplierBase .= $multiplier->getFractionalPart(); } else { $multiplierBase = ltrim($multiplier->getFractionalPart(), '0'); } $resultBase = gmp_strval(gmp_mul(gmp_init($amount), gmp_init($multiplierBase))); if ($resultBase === '0') { return '0'; } $result = substr($resultBase, $decimalPlaces * -1); $resultLength = strlen($result); if ($decimalPlaces > $resultLength) { return '0.' . str_pad('', $decimalPlaces - $resultLength, '0') . $result; } $finalResult = substr($resultBase, 0, $decimalPlaces * -1) . '.' . $result; if ($negativeZero) { // @phpstan-ignore possiblyImpure.functionCall (see https://github.com/phpstan/phpstan/issues/11884) $finalResult = str_replace('-.', '-0.', $finalResult); } return $finalResult; } return gmp_strval(gmp_mul(gmp_init($amount), gmp_init((string) $multiplier))); } /** @phpstan-pure */ public static function divide(string $amount, string $divisor): string { if (self::compare($divisor, '0') === 0) { throw InvalidArgumentException::divisionByZero(); } $divisor = Number::fromString($divisor); if ($divisor->isDecimal()) { $decimalPlaces = strlen($divisor->getFractionalPart()); $divisorBase = $divisor->getIntegerPart(); $negativeZero = $divisorBase === '-0'; if ($negativeZero) { $divisorBase = '-'; } if ($divisor->getIntegerPart()) { $divisor = new Number($divisorBase . $divisor->getFractionalPart()); } else { $divisor = new Number(ltrim($divisor->getFractionalPart(), '0')); } $amount = gmp_strval(gmp_mul(gmp_init($amount), gmp_init('1' . str_pad('', $decimalPlaces, '0')))); } [$integer, $remainder] = gmp_div_qr(gmp_init($amount), gmp_init((string) $divisor)); if (gmp_cmp($remainder, '0') === 0) { return gmp_strval($integer); } $divisionOfRemainder = gmp_strval( gmp_div_q( gmp_mul($remainder, gmp_init('1' . str_pad('', self::SCALE, '0'))), gmp_init((string) $divisor), GMP_ROUND_MINUSINF ) ); if ($divisionOfRemainder[0] === '-') { $divisionOfRemainder = substr($divisionOfRemainder, 1); } return gmp_strval($integer) . '.' . str_pad($divisionOfRemainder, self::SCALE, '0', STR_PAD_LEFT); } /** @phpstan-pure */ public static function ceil(string $number): string { $number = Number::fromString($number); if ($number->isInteger()) { return $number->__toString(); } if ($number->isNegative()) { return self::add($number->getIntegerPart(), '0'); } return self::add($number->getIntegerPart(), '1'); } /** @phpstan-pure */ public static function floor(string $number): string { $number = Number::fromString($number); if ($number->isInteger()) { return $number->__toString(); } if ($number->isNegative()) { return self::add($number->getIntegerPart(), '-1'); } return self::add($number->getIntegerPart(), '0'); } /** * @phpstan-pure */ public static function absolute(string $number): string { return ltrim($number, '-'); } /** * @phpstan-param Money::ROUND_* $roundingMode * * @phpstan-return numeric-string * * @phpstan-pure */ public static function round(string $number, int $roundingMode): string { $number = Number::fromString($number); if ($number->isInteger()) { return $number->__toString(); } if ($number->isHalf() === false) { return self::roundDigit($number); } if ($roundingMode === Money::ROUND_HALF_UP) { return self::add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } if ($roundingMode === Money::ROUND_HALF_DOWN) { return self::add($number->getIntegerPart(), '0'); } if ($roundingMode === Money::ROUND_HALF_EVEN) { if ($number->isCurrentEven()) { return self::add($number->getIntegerPart(), '0'); } return self::add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } if ($roundingMode === Money::ROUND_HALF_ODD) { if ($number->isCurrentEven()) { return self::add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } return self::add($number->getIntegerPart(), '0'); } if ($roundingMode === Money::ROUND_HALF_POSITIVE_INFINITY) { if ($number->isNegative()) { return self::add( $number->getIntegerPart(), '0' ); } return self::add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } if ($roundingMode === Money::ROUND_HALF_NEGATIVE_INFINITY) { if ($number->isNegative()) { return self::add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } return self::add( $number->getIntegerPart(), '0' ); } throw new CoreInvalidArgumentException('Unknown rounding mode'); } /** * @phpstan-return numeric-string * * @phpstan-pure */ private static function roundDigit(Number $number): string { if ($number->isCloserToNext()) { return self::add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } return self::add($number->getIntegerPart(), '0'); } /** @phpstan-pure */ public static function share(string $amount, string $ratio, string $total): string { return self::floor(self::divide(self::multiply($amount, $ratio), $total)); } /** @phpstan-pure */ public static function mod(string $amount, string $divisor): string { if (self::compare($divisor, '0') === 0) { throw InvalidArgumentException::moduloByZero(); } // gmp_mod() only calculates non-negative integers, so we use absolutes $remainder = gmp_mod(self::absolute($amount), self::absolute($divisor)); // If the amount was negative, we negate the result of the modulus operation $amount = Number::fromString($amount); if ($amount->isNegative()) { $remainder = gmp_neg($remainder); } return gmp_strval($remainder); } } PK[$W]„BPCŸŸ#src/Calculator/BcMathCalculator.phpnu„[µü¤isInteger()) { return $number->__toString(); } if ($number->isNegative()) { return bcadd($number->__toString(), '0', 0); } return bcadd($number->__toString(), '1', 0); } /** @phpstan-pure */ public static function floor(string $number): string { $number = Number::fromString($number); if ($number->isInteger()) { return $number->__toString(); } if ($number->isNegative()) { return bcadd($number->__toString(), '-1', 0); } return bcadd($number->__toString(), '0', 0); } /** * @phpstan-pure */ public static function absolute(string $number): string { return ltrim($number, '-'); } /** * @phpstan-param Money::ROUND_* $roundingMode * * @phpstan-return numeric-string * * @phpstan-pure */ public static function round(string $number, int $roundingMode): string { $number = Number::fromString($number); if ($number->isInteger()) { return $number->__toString(); } if ($number->isHalf() === false) { return self::roundDigit($number); } if ($roundingMode === Money::ROUND_HALF_UP) { return bcadd( $number->__toString(), $number->getIntegerRoundingMultiplier(), 0 ); } if ($roundingMode === Money::ROUND_HALF_DOWN) { return bcadd($number->__toString(), '0', 0); } if ($roundingMode === Money::ROUND_HALF_EVEN) { if ($number->isCurrentEven()) { return bcadd($number->__toString(), '0', 0); } return bcadd( $number->__toString(), $number->getIntegerRoundingMultiplier(), 0 ); } if ($roundingMode === Money::ROUND_HALF_ODD) { if ($number->isCurrentEven()) { return bcadd( $number->__toString(), $number->getIntegerRoundingMultiplier(), 0 ); } return bcadd($number->__toString(), '0', 0); } if ($roundingMode === Money::ROUND_HALF_POSITIVE_INFINITY) { if ($number->isNegative()) { return bcadd($number->__toString(), '0', 0); } return bcadd( $number->__toString(), $number->getIntegerRoundingMultiplier(), 0 ); } if ($roundingMode === Money::ROUND_HALF_NEGATIVE_INFINITY) { if ($number->isNegative()) { return bcadd( $number->__toString(), $number->getIntegerRoundingMultiplier(), 0 ); } return bcadd( $number->__toString(), '0', 0 ); } throw new CoreInvalidArgumentException('Unknown rounding mode'); } /** * @phpstan-return numeric-string * * @phpstan-pure */ private static function roundDigit(Number $number): string { if ($number->isCloserToNext()) { return bcadd( $number->__toString(), $number->getIntegerRoundingMultiplier(), 0 ); } return bcadd($number->__toString(), '0', 0); } /** @phpstan-pure */ public static function share(string $amount, string $ratio, string $total): string { return self::floor(bcdiv(bcmul($amount, $ratio, self::SCALE), $total, self::SCALE)); } /** * @phpstan-pure */ public static function mod(string $amount, string $divisor): string { if (bccomp($divisor, '0') === 0) { throw InvalidArgumentException::moduloByZero(); } return bcmod($amount, $divisor); } } PK[$W]Õb:F/F/src/Teller.phpnu„[µü¤convertToMoney($amount)->equals( $this->convertToMoney($other) ); } /** * Returns an integer less than, equal to, or greater than zero if a * monetary amount is respectively less than, equal to, or greater than * another. * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ public function compare(mixed $amount, mixed $other): int { return $this->convertToMoney($amount)->compare( $this->convertToMoney($other) ); } /** * Is one monetary amount greater than another? * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ public function greaterThan(mixed $amount, mixed $other): bool { return $this->convertToMoney($amount)->greaterThan( $this->convertToMoney($other) ); } /** * Is one monetary amount greater than or equal to another? * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ public function greaterThanOrEqual(mixed $amount, mixed $other): bool { return $this->convertToMoney($amount)->greaterThanOrEqual( $this->convertToMoney($other) ); } /** * Is one monetary amount less than another? * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ public function lessThan(mixed $amount, mixed $other): bool { return $this->convertToMoney($amount)->lessThan( $this->convertToMoney($other) ); } /** * Is one monetary amount less than or equal to another? * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ public function lessThanOrEqual(mixed $amount, mixed $other): bool { return $this->convertToMoney($amount)->lessThanOrEqual( $this->convertToMoney($other) ); } /** * Adds a series of monetary amounts to each other in sequence. * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount * @param mixed $others subsequent other monetary amounts * * @return string the calculated monetary amount */ public function add(mixed $amount, mixed $other, mixed ...$others): string { return $this->convertToString( $this->convertToMoney($amount)->add( $this->convertToMoney($other), ...$this->convertToMoneyArray($others) ) ); } /** * Subtracts a series of monetary amounts from each other in sequence. * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount * @param mixed $others subsequent monetary amounts */ public function subtract(mixed $amount, mixed $other, mixed ...$others): string { return $this->convertToString( $this->convertToMoney($amount)->subtract( $this->convertToMoney($other), ...$this->convertToMoneyArray($others) ) ); } /** * Multiplies a monetary amount by a factor. * * @param mixed $amount a monetary amount * @param int|float|numeric-string $multiplier the multiplier */ public function multiply(mixed $amount, int|float|string $multiplier): string { $multiplier = is_float($multiplier) ? Number::fromFloat($multiplier) : Number::fromNumber($multiplier); return $this->convertToString( $this->convertToMoney($amount)->multiply( (string) $multiplier, $this->roundingMode ) ); } /** * Divides a monetary amount by a divisor. * * @param mixed $amount a monetary amount * @param int|float|numeric-string $divisor the divisor */ public function divide(mixed $amount, int|float|string $divisor): string { $divisor = is_float($divisor) ? Number::fromFloat($divisor) : Number::fromNumber($divisor); return $this->convertToString( $this->convertToMoney($amount)->divide( (string) $divisor, $this->roundingMode ) ); } /** * Mods a monetary amount by a divisor. * * @param mixed $amount a monetary amount * @param int|float|numeric-string $divisor the divisor */ public function mod(mixed $amount, int|float|string $divisor): string { $divisor = is_float($divisor) ? Number::fromFloat($divisor) : Number::fromNumber($divisor); return $this->convertToString( $this->convertToMoney($amount)->mod( $this->convertToMoney((string) $divisor) ) ); } /** * Allocates a monetary amount according to an array of ratios. * * @param mixed $amount a monetary amount * @param non-empty-array $ratios an array of ratios * * @return string[] the calculated monetary amounts */ public function allocate(mixed $amount, array $ratios): array { return $this->convertToStringArray( $this->convertToMoney($amount)->allocate($ratios) ); } /** * Allocates a monetary amount among N targets. * * @param mixed $amount a monetary amount * @phpstan-param positive-int $n the number of targets * * @return string[] the calculated monetary amounts */ public function allocateTo(mixed $amount, int $n): array { return $this->convertToStringArray( $this->convertToMoney($amount)->allocateTo($n) ); } /** * Determines the ratio of one monetary amount to another. * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ public function ratioOf(mixed $amount, mixed $other): string { return $this->convertToString( $this->convertToMoney($amount)->ratioOf( $this->convertToMoney($other) ) ); } /** * Returns an absolute monetary amount. * * @param mixed $amount a monetary amount */ public function absolute(mixed $amount): string { return $this->convertToString( $this->convertToMoney($amount)->absolute() ); } /** * Returns the negative of an amount; note that this will convert negative * amounts to positive ones. * * @param mixed $amount a monetary amount */ public function negative(mixed $amount): string { return $this->convertToString( $this->convertToMoney($amount)->negative() ); } /** * Is a monetary amount equal to zero? * * @param mixed $amount a monetary amount */ public function isZero(mixed $amount): bool { return $this->convertToMoney($amount)->isZero(); } /** * Is a monetary amount greater than zero? * * @param mixed $amount a monetary amount */ public function isPositive(mixed $amount): bool { return $this->convertToMoney($amount)->isPositive(); } /** * Is a monetary amount less than zero? * * @param mixed $amount a monetary amount */ public function isNegative(mixed $amount): bool { return $this->convertToMoney($amount)->isNegative(); } /** * Returns the lowest of a series of monetary amounts. * * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts */ public function min(mixed $amount, mixed ...$amounts): string { return $this->convertToString( Money::min( $this->convertToMoney($amount), ...$this->convertToMoneyArray($amounts) ) ); } /** * Returns the highest of a series of monetary amounts. * * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts */ public function max(mixed $amount, mixed ...$amounts): string { return $this->convertToString( Money::max( $this->convertToMoney($amount), ...$this->convertToMoneyArray($amounts) ) ); } /** * Returns the sum of a series of monetary amounts. * * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts */ public function sum(mixed $amount, mixed ...$amounts): string { return $this->convertToString( Money::sum( $this->convertToMoney($amount), ...$this->convertToMoneyArray($amounts) ) ); } /** * Returns the average of a series of monetary amounts. * * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts */ public function avg(mixed $amount, mixed ...$amounts): string { return $this->convertToString( Money::avg( $this->convertToMoney($amount), ...$this->convertToMoneyArray($amounts) ) ); } /** * Converts a monetary amount to a Money object. * * @param mixed $amount a monetary amount */ public function convertToMoney(mixed $amount): Money { return $this->parser->parse((string) $amount, $this->currency); } /** * Converts an array of monetary amounts to an array of Money objects. * * @param array $amounts an array of monetary amounts * * @return Money[] */ public function convertToMoneyArray(array $amounts): array { $converted = []; /** @var mixed $amount */ foreach ($amounts as $key => $amount) { $converted[$key] = $this->convertToMoney($amount); } return $converted; } /** * Converts a monetary amount into a Money object, then into a string. * * @param mixed $amount typically a Money object, int, float, or string * representing a monetary amount */ public function convertToString(mixed $amount): string { if ($amount instanceof Money === false) { $amount = $this->convertToMoney($amount); } return $this->formatter->format($amount); } /** * Converts an array of monetary amounts into Money objects, then into * strings. * * @param array $amounts an array of monetary amounts * * @return string[] */ public function convertToStringArray(array $amounts): array { $converted = []; /** @var mixed $amount */ foreach ($amounts as $key => $amount) { $converted[$key] = $this->convertToString($amount); } return $converted; } /** * Returns a "zero" monetary amount. */ public function zero(): string { return '0.00'; } } PK[$W]• `sdd$src/Currencies/BitcoinCurrencies.phpnu„[µü¤getCode() === self::CODE; } public function subunitFor(Currency $currency): int { if ($currency->getCode() !== self::CODE) { throw new UnknownCurrencyException($currency->getCode() . ' is not bitcoin and is not supported by this currency repository'); } return 8; } /** {@inheritDoc} */ public function getIterator(): Traversable { return new ArrayIterator([new Currency(self::CODE)]); } } PK[$W]ùxì= = #src/Currencies/CryptoCurrencies.phpnu„[µü¤|null */ private static array|null $currencies = null; public function contains(Currency $currency): bool { return isset($this->getCurrencies()[$currency->getCode()]); } public function subunitFor(Currency $currency): int { if (! $this->contains($currency)) { throw new UnknownCurrencyException('Cannot find ISO currency ' . $currency->getCode()); } return $this->getCurrencies()[$currency->getCode()]['minorUnit']; } /** * @phpstan-return Traversable */ public function getIterator(): Traversable { return new ArrayIterator( array_map( static function ($code) { return new Currency($code); }, array_keys($this->getCurrencies()) ) ); } /** * Returns a map of known currencies indexed by code. * * @phpstan-return non-empty-array */ private function getCurrencies(): array { if (self::$currencies === null) { self::$currencies = $this->loadCurrencies(); } return self::$currencies; } /** * @phpstan-return non-empty-array */ private function loadCurrencies(): array { $file = __DIR__ . '/../../resources/binance.php'; if (is_file($file)) { return require $file; } throw new RuntimeException('Failed to load currency ISO codes.'); } } PK[$W]@ç­gJJ#src/Currencies/CachedCurrencies.phpnu„[µü¤pool->getItem('currency|availability|' . $currency->getCode()); if ($item->isHit() === false) { $item->set($this->currencies->contains($currency)); if ($item instanceof TaggableCacheItemInterface) { $item->setTags(['currency.availability']); } $this->pool->save($item); } return (bool) $item->get(); } public function subunitFor(Currency $currency): int { $item = $this->pool->getItem('currency|subunit|' . $currency->getCode()); if ($item->isHit() === false) { $item->set($this->currencies->subunitFor($currency)); if ($item instanceof TaggableCacheItemInterface) { $item->setTags(['currency.subunit']); } $this->pool->save($item); } return (int) $item->get(); } /** {@inheritDoc} */ public function getIterator(): Traversable { return new CallbackFilterIterator( new ArrayIterator(iterator_to_array($this->currencies->getIterator())), function (Currency $currency): bool { $item = $this->pool->getItem('currency|availability|' . $currency->getCode()); $item->set(true); if ($item instanceof TaggableCacheItemInterface) { $item->setTags(['currency.availability']); } $this->pool->save($item); return true; } ); } } PK[$W]jºÜGsrc/Currencies/CurrencyList.phpnu„[µü¤ */ private array $currencies; /** @phpstan-param array $currencies */ public function __construct(array $currencies) { $this->currencies = $currencies; } public function contains(Currency $currency): bool { return isset($this->currencies[$currency->getCode()]); } public function subunitFor(Currency $currency): int { if (! $this->contains($currency)) { throw new UnknownCurrencyException('Cannot find currency ' . $currency->getCode()); } return $this->currencies[$currency->getCode()]; } /** {@inheritDoc} */ public function getIterator(): Traversable { return new ArrayIterator( array_map( static function ($code) { return new Currency($code); }, array_keys($this->currencies) ) ); } } PK[$W]Jìb¬ô ô src/Currencies/ISOCurrencies.phpnu„[µü¤|null */ private static array|null $currencies = null; public function contains(Currency $currency): bool { return isset($this->getCurrencies()[$currency->getCode()]); } public function subunitFor(Currency $currency): int { if (! $this->contains($currency)) { throw new UnknownCurrencyException('Cannot find ISO currency ' . $currency->getCode()); } return $this->getCurrencies()[$currency->getCode()]['minorUnit']; } /** * Returns the numeric code for a currency. * * @throws UnknownCurrencyException If currency is not available in the current context. */ public function numericCodeFor(Currency $currency): int { if (! $this->contains($currency)) { throw new UnknownCurrencyException('Cannot find ISO currency ' . $currency->getCode()); } return $this->getCurrencies()[$currency->getCode()]['numericCode']; } /** * @phpstan-return Traversable */ public function getIterator(): Traversable { return new ArrayIterator( array_map( static function ($code) { return new Currency($code); }, array_keys($this->getCurrencies()) ) ); } /** * Returns a map of known currencies indexed by code. * * @phpstan-return non-empty-array */ private function getCurrencies(): array { if (self::$currencies === null) { self::$currencies = $this->loadCurrencies(); } return self::$currencies; } /** * @phpstan-return non-empty-array */ private function loadCurrencies(): array { $file = __DIR__ . '/../../resources/currency.php'; if (is_file($file)) { return require $file; } throw new RuntimeException('Failed to load currency ISO codes.'); } } PK[$W]=V¿áJJ&src/Currencies/AggregateCurrencies.phpnu„[µü¤currencies as $currencies) { if ($currencies->contains($currency)) { return true; } } return false; } public function subunitFor(Currency $currency): int { foreach ($this->currencies as $currencies) { if ($currencies->contains($currency)) { return $currencies->subunitFor($currency); } } throw new UnknownCurrencyException('Cannot find currency ' . $currency->getCode()); } /** {@inheritDoc} */ public function getIterator(): Traversable { $iterator = new AppendIterator(); foreach ($this->currencies as $currencies) { $iterator->append(new IteratorIterator($currencies->getIterator())); } return $iterator; } } PK[$W]fÕ11src/Currency.phpnu„[µü¤code = strtoupper($code); } /** * Returns the currency code. * * @phpstan-return non-empty-string */ public function getCode(): string { return $this->code; } /** * Checks whether this currency is the same as an other. */ public function equals(Currency $other): bool { return $this->code === $other->code; } public function __toString(): string { return $this->code; } public function jsonSerialize(): string { return $this->code; } } PK[$W]F˜ Ë77src/MoneyFormatter.phpnu„[µü¤register(new \Money\PHPUnit\Comparator()); * * @internal do not use within your sources: this comparator is only to be used within the test suite of this library */ final class Comparator extends \SebastianBergmann\Comparator\Comparator { private IntlMoneyFormatter $formatter; public function __construct() { $currencies = new AggregateCurrencies([ new ISOCurrencies(), new BitcoinCurrencies(), ]); $numberFormatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY); $this->formatter = new IntlMoneyFormatter($numberFormatter, $currencies); } /** {@inheritDoc} */ public function accepts(mixed $expected, mixed $actual): bool { return $expected instanceof Money && $actual instanceof Money; } /** * {@inheritDoc} * * @param float $delta * @param bool $canonicalize * @param bool $ignoreCase */ public function assertEquals( mixed $expected, mixed $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false ): void { assert($expected instanceof Money); assert($actual instanceof Money); if (! $expected->equals($actual)) { throw new ComparisonFailure($expected, $actual, $this->formatter->format($expected), $this->formatter->format($actual), 'Failed asserting that two Money objects are equal.'); } } } PK[$W]çaÒº>>src/Exchange.phpnu„[µü¤ $b. * Retrieves zero if $a == $b * * @phpstan-param numeric-string $a * @phpstan-param numeric-string $b * * @phpstan-pure */ public static function compare(string $a, string $b): int; /** * Add added to amount. * * @phpstan-param numeric-string $amount * @phpstan-param numeric-string $addend * * @phpstan-return numeric-string * * @phpstan-pure */ public static function add(string $amount, string $addend): string; /** * Subtract subtrahend from amount. * * @phpstan-param numeric-string $amount * @phpstan-param numeric-string $subtrahend * * @phpstan-return numeric-string * * @phpstan-pure */ public static function subtract(string $amount, string $subtrahend): string; /** * Multiply amount with multiplier. * * @phpstan-param numeric-string $amount * @phpstan-param numeric-string $multiplier * * @phpstan-return numeric-string * * @phpstan-pure */ public static function multiply(string $amount, string $multiplier): string; /** * Divide amount with divisor. * * @phpstan-param numeric-string $amount * @phpstan-param numeric-string $divisor * * @phpstan-return numeric-string * * @throws InvalidArgumentException when $divisor is zero. * * @phpstan-pure */ public static function divide(string $amount, string $divisor): string; /** * Round number to following integer. * * @phpstan-param numeric-string $number * * @phpstan-return numeric-string * * @phpstan-pure */ public static function ceil(string $number): string; /** * Round number to preceding integer. * * @phpstan-param numeric-string $number * * @phpstan-return numeric-string * * @phpstan-pure */ public static function floor(string $number): string; /** * Returns the absolute value of the number. * * @phpstan-param numeric-string $number * * @phpstan-return numeric-string * * @phpstan-pure */ public static function absolute(string $number): string; /** * Round number, use rounding mode for tie-breaker. * * @phpstan-param numeric-string $number * @phpstan-param Money::ROUND_* $roundingMode * * @phpstan-return numeric-string * * @phpstan-pure */ public static function round(string $number, int $roundingMode): string; /** * Share amount among ratio / total portions. * * @phpstan-param numeric-string $amount * @phpstan-param numeric-string $ratio * @phpstan-param numeric-string $total * * @phpstan-return numeric-string * * @phpstan-pure */ public static function share(string $amount, string $ratio, string $total): string; /** * Get the modulus of an amount. * * @phpstan-param numeric-string $amount * @phpstan-param numeric-string $divisor * * @phpstan-return numeric-string * * @throws InvalidArgumentException when $divisor is zero. * * @phpstan-pure */ public static function mod(string $amount, string $divisor): string; } PK[$W]Å@ D§§src/TellerFactory.phpnu„[µü¤ * $teller = Teller::USD(); * * * @param non-empty-string $method * @param array{0?: Money::ROUND_*} $arguments */ public static function __callStatic(string $method, array $arguments): Teller { $currency = new Currency($method); $currencies = new ISOCurrencies(); $parser = new DecimalMoneyParser($currencies); $formatter = new DecimalMoneyFormatter($currencies); $roundingMode = empty($arguments) ? Money::ROUND_HALF_UP : (int) array_shift($arguments); return new Teller( $currency, $parser, $formatter, $roundingMode ); } } PK[$W]–••phpcs.xml.distnu„[µü¤ ./src ./static-analysis ./tests PK[$W]+8ÿh=h= CHANGELOG.mdnu„[µü¤# Change Log All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [4.8.0] - 2025-10-23 ### Added - PHP 8.5 support ## [4.7.1] - 2025-06-06 ### Updated - Updated the ISO and Crypto currencies ## [4.7.0] - 2025-04-03 ### Added - Subtypes of InvalidArgumentException ## [4.6.0] - 2024-11-22 ### Added - PHP 8.4 support ## [4.5.0] - 2024-02-15 ### Fixed - PHPUnit 10 support - Update currencies - Updated doctrine/coding-standard - Updated other dev dependencies ### Removed - PHP 8.0 support ## [4.4.0] - 2024-01-24 ### Added - Extended support for psr/cache, now version 1.0.1 up until 3.0 is supported. ## [4.3.0] - 2023-11-22 ### Added - Support for PHP 8.3 - Allow divisor in mod to be a number as well ### Removed - PHPSpec tests, we are using PHPUnit only now ## [4.2.0] - 2023-08-16 ### Added - Teller object to help legacy applications ## [4.1.1] - 2023-04-11 ### Fixed - Optimized result representation for BcMathCalculator - Use sprintf for float to string conversion in swap exchange - Fix rounding to unit with value between 10 and 49 - Return type for DecimalMoneyFormatter::format is numeric-string - Money::ratioOf throws exception if currencies don't match. - Updated currencies: added SLE and VED, removed HRK. - Do not let php-http/discovery change composer.json. ## [4.1.0] - 2022-12-19 ### Added - Full PHP8.2 compatibility ### Fixed - Fix parsing amounts with leading zero's - Fix invalid exception message in DecimalMoneyParser - Upgrade enchant to newer version - Support Psalm 5.3 - Fix ROUND_UP and ROUND_DOWN in roundToUnit ### Changes - `composer.lock` is not committed anymore - MoneyFactory now also contains crypto-currencies ### Added - `CryptoCurrencies` class that serves crypto-currencies from [moneyphp/crypto-currencies](https://github.com/moneyphp/crypto-currencies) ## [4.0.5] - 2022-08-11 ### Fixed - Enabled zend.assertions during CI - Fixed invalid assertions ## [4.0.4] - 2022-05-18 ### Added - Full PHP8.1 compatibility (#670) ### Changes - Dropped mutation testing as the library owners are unfamiliar with it - CHANGELOG BC change improvement ## [4.0.3] - 2021-12-01 ### Fixed - `jsonSerialize` return types, resulting in no PHP 8.1 warnings. - Documentation CI pipeline failure. ## [4.0.2] - 2021-06-30 ### Changes - Added all extensions to `composer.json`, including those bundled with PHP. ### Fixed - Remove all `empty` uses. Money values of '0' gave an assertion error in decimal formats (#655) ## [4.0.1] - 2021-05-25 ### Changed - Allow `int` as multiplier for `Money::multiply` - Allow `int` as divisor for `Money::divide` ## [4.0.0] - 2021-05-17 ### Added - PHP8.0 compatibility (#633 and #619) - Recommendation to use a type-checker like psalm or phpstan - Rounding to units - `Converter#convertAndReturnWithCurrencyPair` to get the combination of the converted money and currency pair - `Converter#convertAgainstCurrencyPair` to convert against a currency pair ### Changed - **[BC break]** BC Math required as it is the default calculator - **[BC break]** The methods `multiply` and `divide` do not accept floating points any more. Callers are required to convert a float to string (e.g. `sprintf('%.14F', $float)`) before calling these methods. - **[BC break]** The constructor of the `FixedExchange` does not accept floating points any more. Callers are required to convert a float to string (e.g. `sprintf('%.14F', $float)`) before calling the constructor. - Allow multiple arguments to `Money#isSameCurrency` - Renamed second parameter of `Parser#parse` to `$fallbackCurrency` ### Fixed - Fix GMP multiply and divide by negative (#640 #626) - Currency code must be uppercase (#639 #638 #637) - The CPU no longer overheats when using this library (#634) - No longer allowing null amount (#615) - Update cached currencies (#583) - Only numeric strings allowed (#575) - Calculator and Number are internal (#465) - Negative ratio in `Money#allocate()` is now allowed (#258) ### Removed - **[BC break]** Removed `PhpCalculator` - **[BC break]** Removed `Currency#isAvailableWithin()` - **[BC break]** Removed string as allowed type for second parameter to `MoneyParser#parse`, only Currency objects are accepted now - **[BC break]** Completely remove float usage, methods now return numeric-strings ## [3.3.1] - 2019-03-13 ### Fixed - GMP: division of negative values - GMP: compare 0.x value ## [3.3.0] - 2019-12-27 ### Changed - Added types for `Money` to be understood as pure/immutable downstream (#576) ### Fixed - JSON serialization (#551) - Several documentation fixes - Minor fixes ## [3.2.1] - 2019-02-07 ### Changed - `Money::allocate` now maintains keys of ratios array - All parsers now emit a deprecation warning when passing currency as string ### Fixed - Docs fix : plus sign in numeric strings is allowed - Added ext-json as required extension - Throw exception in case of empty currency - BCMath calculator now uses scale parameters for addition and subtracting - Fixed allocation remainder bug - Added PHP 7.3 in test suite - Fixed dockerignore to ignore Dockerfile - Fixed Bitcoin parsing bug when using trailing zeros ## [3.2.0] - 2018-12-05 ### Added - [Exchanger](https://github.com/florianv/exchanger) exchange - Generated static factory to help IDEs understand code like `Money::EUR(500)` - Aggregation functions (min, max, avg, sum) ### Changed - `Money::add` and `Money::subtract` now accept variadic arguments ### Fixed - Division causing unnecessary fractional parts - Numeric comparison for negative numbers ## [3.1.3] - 2018-02-16 ### Fixed - Allocation when the amount is smaller than the number of ratios ## [3.1.2] - 2018-02-16 ### Added - `Number::fromNumber` to be used when the actual type is not known ### Changed - Refactored `Number` usage to make the code cleaner and use less casting ### Fixed - Float cast to string issue on certain locales ## [3.1.1] - 2018-01-19 ### Fixed - Float cast to string issue on certain locales - Deal with numbers represented with E-XX ## [3.1.0] - 2018-01-10 ### Added - CurrencyList to instantiate in-memory currencies - modulus method to Money - ratioOf method to Money - Comparator for easier testing Money object with PHPUnit - IntlLocalizedDecimalParser and IntlLocalizedDecimalFormatter ### Changed - `MoneyParser::parse` method now expects a Currency object - Dropped PHP 5.5 ### Deprecated - Passing currency code as string to `MoneyParser::parse` ### Fixed - Do not allocate remainder to a ratio of zero - Conversion result is always 0 when subunit difference is large enough - Unexpected result when converting small Bitcoin amounts - Fixed StyleCI being too aggressive ## [3.0.9] - 2017-11-05 ### Fixed - Bitcoin currency symbol ## [3.0.8] - 2017-10-03 ### Fixed - Rounding issue in Number class. - Reduce composer package file size by leaving out docs and logo. - Missing Travis tests for PHP 7.2. ## [3.0.7] - 2017-08-07 ### Changed - Currencies ## [3.0.6] - 2017-07-25 ### Added - IndirectExchange: a way to get an exchange rate through a minimal set of intermediate conversions. ### Fixed - Tests for HHVM - Incorrect documentation on Bitcoin parser ## [3.0.5] - 2017-04-26 ### Added - numericCodeFor method to ISOCurrencies ## [3.0.4] - 2017-04-21 ### Added - Negative method ### Changed - Updated ISO Currencies - Removed old Belarusian ruble from ISOCurrencies (BYR) ### Fixed - ISOCurrencies will no longer have a blank currency - Double symbol when formatting negative Bitcoin amounts ## [3.0.3] - 2017-03-22 ### Fixed - Parsing empty strings and number starting or ending with a decimal point for DecimalMoneyParser - Parsing zero for DecimalMoneyParser - Multiplying and dividing with a locale that use commas as separator ## [3.0.2] - 2017-03-11 ### Fixed - BCMath / GMP: comparing values smaller than one - GMP: multiplying with zero - ISOCurrencies: minor refactoring, remove duplication of code ## [3.0.1] - 2017-02-14 ### Added - Reversed Currencies Exchange to try resolving reverse of a currency pair - Documentation on allowed integer(ish) values when constructing Money ### Fixed - Passing integer validation when chunk started with a dash - Passing integer validation when the fractional part started with a dash - Formatting problem for Bitcoin currency with small amounts in PHP < 7.0 - Money constructed from a string with fractional zeroes equals to a Money constructed without the fractional part (eg. `'5.00'` and `'5'`) ## [3.0.0] - 2016-10-26 ### Added - DecimalMoneyFormatter: returns locale-independent raw decimal string ### Changed - **[BC break]** Replaced StringToUnitsParser with DecimalMoneyParser - **[BC break]** Moved `Money\Exception\Exception` to `Money\Exception` - **[BC break]** UnkownCurrencyException is now DomainException instead of RuntimeException - **[Doctrine break]** In `Currency` the private variable `name` was renamed to `code`, which could break your Doctrine mapping if you are using embeddables or any other Reflection related implementation. ## [3.0.0-beta.3] - 2016-10-04 ### Added - FixedExchange: returns fixed exchange rates based on a list (array) ### Changed - **[BC break]** Convert method now moved to its own class: Converter - **[BC break]** Exchange had one method getCurrencyPair which is now renamed to quote - Minor documentation issues ### Fixed - Integer detection when the number overflows the integer type and contains zeros - Rounding numbers containg trailing zeros - Converting Money to currency with different number of subunits ## [3.0.0-beta.2] - 2016-08-03 ### Added - PHP Spec tests - absolute method to Money and Calculator - subunitFor method to Currencies - Currencies now extends IteratorAggregate - Library exceptions now implement a common interface - Formatter and Parser implementation are now rounding half up ### Changed - **[BC break]** Dropped PHP 5.4 support - **[BC break]** Intl and Bitcoin formatters and parsers now require Currencies - ISOCurrencies now uses moneyphp/iso-currencies as currency data source ### Fixed - Documentation to be inline with upcoming version 3 - Rounding issues in calculators with negative numbers - Formatting and parser issues for amounts and numbers with a trailing zero - Improved many exception messages - Registration of own Calculator implementations ## [3.0.0-beta] - 2016-03-01 ### Added - Bitcoin parser and formatter - Also checking tests folder for StyleCI ### Fixed - Currencies are now included in the repo - Currency list generation moved to dev dependency: reduces repo size - BC Math calculator adding and subtracting failed when bcscale was set - Parsing zero for StringToUnitsParser ## 3.0.0-alpha - 2016-02-04 ### Added - Currency repositories (ISO currencies included) - Money exchange (including [Swap](https://github.com/florianv/swap) implementation) - Money formatting (including intl formatter) - Money parsing (including intl parser) - Big integer support utilizing different, transparent calculation logic upon availability (bcmath, gmp, plain php) - Money and Currency implements JsonSerializable - Rounding up and down - Allocation to N targets ### Changed - **[BC break]** Money::getAmount() returns a string instead of an int value - **[BC break]** Moved stringToUnits to StringToUnitsParser parser - Library requires at least PHP 5.4 - Library uses PSR-4 ### Fixed - Integer overflow ### Removed - **[BC break]** UnkownCurrency exception - **[BC break]** Currency list is now provided by [umpirsky/currency-list](https://github.com/umpirsky/currency-list/) - **[BC break]** RoundingMode class - **[BC break]** Announced deprecations are removed (Currency::getName, CurrencyPair::getRatio, Money::getUnits) ## Pre 3.0 - 2015-03-23 Minimum php version is now 5.4 - 2015-03-23 JsonSerializable - (... missing changelog because who remembers to document stuff anyway?) - 2014-03-22 Removed \Money\InvalidArgumentException in favour of plain old InvalidArgumentException - 2014-03-22 Introduce RoundingMode object, used to specify desired rounding - 2014-03-22 Introduced RoundingMode backwards compatible API changes to Money::multiply and Money::divide - 2014-03-22 Allow RoundingMode to be specified when converting currencies - 2014-03-22 CurrencyPair has an equals() method - 2013-10-13 Base currency and counter currency in CurrencyPair named correctly. - 2013-01-08 Removed the Doctrine2\MoneyType helper, to be replaced by something better in the future. It's available at https://gist.github.com/4485025 in case you need it. - 2013-01-08 Use vendor/autoload.php instead of lib/bootstrap.php (or use PSR-0 autolaoding) - 2012-12-10 Renamed Money::getUnits() to Money::getAmount() [Unreleased]: https://github.com/moneyphp/money/compare/v4.4.0...HEAD [4.8.0]: https://github.com/moneyphp/money/compare/v4.7.1...v4.8.0 [4.7.1]: https://github.com/moneyphp/money/compare/v4.7.0...v4.7.1 [4.7.0]: https://github.com/moneyphp/money/compare/v4.6.0...v4.7.0 [4.6.0]: https://github.com/moneyphp/money/compare/v4.5.0...v4.6.0 [4.5.0]: https://github.com/moneyphp/money/compare/v4.4.0...v4.5.0 [4.4.0]: https://github.com/moneyphp/money/compare/v4.3.0...v4.4.0 [4.3.0]: https://github.com/moneyphp/money/compare/v4.2.0...v4.3.0 [4.2.0]: https://github.com/moneyphp/money/compare/v4.1.1...v4.2.0 [4.1.1]: https://github.com/moneyphp/money/compare/v4.1.0...v4.1.1 [4.1.0]: https://github.com/moneyphp/money/compare/v4.0.5...v4.1.0 [4.0.5]: https://github.com/moneyphp/money/compare/v4.0.4...v4.0.5 [4.0.4]: https://github.com/moneyphp/money/compare/v4.0.3...v4.0.4 [4.0.3]: https://github.com/moneyphp/money/compare/v4.0.2...v4.0.3 [4.0.2]: https://github.com/moneyphp/money/compare/v4.0.1...v4.0.2 [4.0.1]: https://github.com/moneyphp/money/compare/v4.0.0...v4.0.1 [4.0.0]: https://github.com/moneyphp/money/compare/v3.3.1...v4.0.0 [3.3.1]: https://github.com/moneyphp/money/compare/v3.3.0...v3.3.1 [3.3.0]: https://github.com/moneyphp/money/compare/v3.2.1...v3.3.0 [3.2.1]: https://github.com/moneyphp/money/compare/v3.2.0...v3.2.1 [3.2.0]: https://github.com/moneyphp/money/compare/v3.1.3...v3.2.0 [3.1.3]: https://github.com/moneyphp/money/compare/v3.1.2...v3.1.3 [3.1.2]: https://github.com/moneyphp/money/compare/v3.1.1...v3.1.2 [3.1.1]: https://github.com/moneyphp/money/compare/v3.1.0...v3.1.1 [3.1.0]: https://github.com/moneyphp/money/compare/v3.0.9...v3.1.0 [3.0.9]: https://github.com/moneyphp/money/compare/v3.0.8...v3.0.9 [3.0.8]: https://github.com/moneyphp/money/compare/v3.0.7...v3.0.8 [3.0.7]: https://github.com/moneyphp/money/compare/v3.0.6...v3.0.7 [3.0.6]: https://github.com/moneyphp/money/compare/v3.0.5...v3.0.6 [3.0.5]: https://github.com/moneyphp/money/compare/v3.0.4...v3.0.5 [3.0.4]: https://github.com/moneyphp/money/compare/v3.0.3...v3.0.4 [3.0.3]: https://github.com/moneyphp/money/compare/v3.0.2...v3.0.3 [3.0.2]: https://github.com/moneyphp/money/compare/v3.0.1...v3.0.2 [3.0.1]: https://github.com/moneyphp/money/compare/v3.0.0...v3.0.1 [3.0.0]: https://github.com/moneyphp/money/compare/v3.0.0-beta.4...v3.0.0 [3.0.0-beta4]: https://github.com/moneyphp/money/compare/v3.0.0-beta.3...v3.0.0-beta.4 [3.0.0-beta3]: https://github.com/moneyphp/money/compare/v3.0.0-beta.2...v3.0.0-beta.3 [3.0.0-beta2]: https://github.com/moneyphp/money/compare/v3.0.0-beta...v3.0.0-beta.2 [3.0.0-beta]: https://github.com/moneyphp/money/compare/v3.0.0-alpha...v3.0.0-beta PK[$W]0®Å­ ­ composer.jsonnu„[µü¤{ "name": "moneyphp/money", "description": "PHP implementation of Fowler's Money pattern", "license": "MIT", "keywords": [ "money", "vo", "value object" ], "authors": [ { "name": "Mathias Verraes", "email": "mathias@verraes.net", "homepage": "http://verraes.net" }, { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com" }, { "name": "Frederik Bosch", "email": "f.bosch@genkgo.nl" } ], "homepage": "http://moneyphp.org", "require": { "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", "ext-bcmath": "*", "ext-filter": "*", "ext-json": "*" }, "require-dev": { "ext-gmp": "*", "ext-intl": "*", "cache/taggable-cache": "^1.1.0", "doctrine/coding-standard": "^12.0", "doctrine/instantiator": "^1.5.0 || ^2.0", "florianv/exchanger": "^2.8.1", "florianv/swap": "^4.3.0", "moneyphp/crypto-currencies": "^1.1.0", "moneyphp/iso-currencies": "^3.4", "php-http/message": "^1.16.0", "php-http/mock-client": "^1.6.0", "phpbench/phpbench": "^1.2.5", "phpstan/extension-installer": "^1.4", "phpstan/phpstan": "^2.1.9", "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpunit": "^10.5.9", "psr/cache": "^1.0.1 || ^2.0 || ^3.0", "ticketswap/phpstan-error-formatter": "^1.1" }, "suggest": { "ext-gmp": "Calculate without integer limits", "ext-intl": "Format Money objects with intl", "florianv/exchanger": "Exchange rates library for PHP", "florianv/swap": "Exchange rates library for PHP", "psr/cache-implementation": "Used for Currency caching" }, "minimum-stability": "dev", "prefer-stable": true, "autoload": { "psr-4": { "Money\\": "src/" } }, "autoload-dev": { "psr-4": { "Benchmark\\Money\\": "benchmark/", "Tests\\Money\\": "tests/" } }, "config": { "allow-plugins": { "composer/package-versions-deprecated": true, "dealerdirect/phpcodesniffer-composer-installer": true, "ergebnis/composer-normalize": true, "infection/extension-installer": true, "php-http/discovery": false, "phpstan/extension-installer": true }, "sort-packages": true }, "extra": { "branch-alias": { "dev-master": "3.x-dev" } }, "scripts": { "benchmark": [ "vendor/bin/phpbench run --retry-threshold=3 --iterations=15 --revs=1000 --warmup=2" ], "clean": "rm -rf build/ vendor/", "test": [ "vendor/bin/phpbench run", "vendor/bin/phpunit", "vendor/bin/phpstan", "vendor/bin/phpcs" ], "test-coverage": [ "vendor/bin/phpunit --coverage-text --coverage-clover=build/unit_coverage.xml" ], "update-currencies": [ "cp vendor/moneyphp/iso-currencies/resources/current.php resources/currency.php", "cp vendor/moneyphp/crypto-currencies/resources/binance.php resources/binance.php", "php resources/generate-money-factory.php", "php resources/generate-teller-factory.php" ] } } PK[$W]òc¶ccresources/currency.phpnu„[µü¤ array ( 'alphabeticCode' => 'AED', 'currency' => 'UAE Dirham', 'minorUnit' => 2, 'numericCode' => 784, ), 'AFN' => array ( 'alphabeticCode' => 'AFN', 'currency' => 'Afghani', 'minorUnit' => 2, 'numericCode' => 971, ), 'ALL' => array ( 'alphabeticCode' => 'ALL', 'currency' => 'Lek', 'minorUnit' => 2, 'numericCode' => 8, ), 'AMD' => array ( 'alphabeticCode' => 'AMD', 'currency' => 'Armenian Dram', 'minorUnit' => 2, 'numericCode' => 51, ), 'AOA' => array ( 'alphabeticCode' => 'AOA', 'currency' => 'Kwanza', 'minorUnit' => 2, 'numericCode' => 973, ), 'ARS' => array ( 'alphabeticCode' => 'ARS', 'currency' => 'Argentine Peso', 'minorUnit' => 2, 'numericCode' => 32, ), 'AUD' => array ( 'alphabeticCode' => 'AUD', 'currency' => 'Australian Dollar', 'minorUnit' => 2, 'numericCode' => 36, ), 'AWG' => array ( 'alphabeticCode' => 'AWG', 'currency' => 'Aruban Florin', 'minorUnit' => 2, 'numericCode' => 533, ), 'AZN' => array ( 'alphabeticCode' => 'AZN', 'currency' => 'Azerbaijan Manat', 'minorUnit' => 2, 'numericCode' => 944, ), 'BAM' => array ( 'alphabeticCode' => 'BAM', 'currency' => 'Convertible Mark', 'minorUnit' => 2, 'numericCode' => 977, ), 'BBD' => array ( 'alphabeticCode' => 'BBD', 'currency' => 'Barbados Dollar', 'minorUnit' => 2, 'numericCode' => 52, ), 'BDT' => array ( 'alphabeticCode' => 'BDT', 'currency' => 'Taka', 'minorUnit' => 2, 'numericCode' => 50, ), 'BGN' => array ( 'alphabeticCode' => 'BGN', 'currency' => 'Bulgarian Lev', 'minorUnit' => 2, 'numericCode' => 975, ), 'BHD' => array ( 'alphabeticCode' => 'BHD', 'currency' => 'Bahraini Dinar', 'minorUnit' => 3, 'numericCode' => 48, ), 'BIF' => array ( 'alphabeticCode' => 'BIF', 'currency' => 'Burundi Franc', 'minorUnit' => 0, 'numericCode' => 108, ), 'BMD' => array ( 'alphabeticCode' => 'BMD', 'currency' => 'Bermudian Dollar', 'minorUnit' => 2, 'numericCode' => 60, ), 'BND' => array ( 'alphabeticCode' => 'BND', 'currency' => 'Brunei Dollar', 'minorUnit' => 2, 'numericCode' => 96, ), 'BOB' => array ( 'alphabeticCode' => 'BOB', 'currency' => 'Boliviano', 'minorUnit' => 2, 'numericCode' => 68, ), 'BOV' => array ( 'alphabeticCode' => 'BOV', 'currency' => 'Mvdol', 'minorUnit' => 2, 'numericCode' => 984, ), 'BRL' => array ( 'alphabeticCode' => 'BRL', 'currency' => 'Brazilian Real', 'minorUnit' => 2, 'numericCode' => 986, ), 'BSD' => array ( 'alphabeticCode' => 'BSD', 'currency' => 'Bahamian Dollar', 'minorUnit' => 2, 'numericCode' => 44, ), 'BTN' => array ( 'alphabeticCode' => 'BTN', 'currency' => 'Ngultrum', 'minorUnit' => 2, 'numericCode' => 64, ), 'BWP' => array ( 'alphabeticCode' => 'BWP', 'currency' => 'Pula', 'minorUnit' => 2, 'numericCode' => 72, ), 'BYN' => array ( 'alphabeticCode' => 'BYN', 'currency' => 'Belarusian Ruble', 'minorUnit' => 2, 'numericCode' => 933, ), 'BZD' => array ( 'alphabeticCode' => 'BZD', 'currency' => 'Belize Dollar', 'minorUnit' => 2, 'numericCode' => 84, ), 'CAD' => array ( 'alphabeticCode' => 'CAD', 'currency' => 'Canadian Dollar', 'minorUnit' => 2, 'numericCode' => 124, ), 'CDF' => array ( 'alphabeticCode' => 'CDF', 'currency' => 'Congolese Franc', 'minorUnit' => 2, 'numericCode' => 976, ), 'CHE' => array ( 'alphabeticCode' => 'CHE', 'currency' => 'WIR Euro', 'minorUnit' => 2, 'numericCode' => 947, ), 'CHF' => array ( 'alphabeticCode' => 'CHF', 'currency' => 'Swiss Franc', 'minorUnit' => 2, 'numericCode' => 756, ), 'CHW' => array ( 'alphabeticCode' => 'CHW', 'currency' => 'WIR Franc', 'minorUnit' => 2, 'numericCode' => 948, ), 'CLF' => array ( 'alphabeticCode' => 'CLF', 'currency' => 'Unidad de Fomento', 'minorUnit' => 4, 'numericCode' => 990, ), 'CLP' => array ( 'alphabeticCode' => 'CLP', 'currency' => 'Chilean Peso', 'minorUnit' => 0, 'numericCode' => 152, ), 'CNY' => array ( 'alphabeticCode' => 'CNY', 'currency' => 'Yuan Renminbi', 'minorUnit' => 2, 'numericCode' => 156, ), 'COP' => array ( 'alphabeticCode' => 'COP', 'currency' => 'Colombian Peso', 'minorUnit' => 2, 'numericCode' => 170, ), 'COU' => array ( 'alphabeticCode' => 'COU', 'currency' => 'Unidad de Valor Real', 'minorUnit' => 2, 'numericCode' => 970, ), 'CRC' => array ( 'alphabeticCode' => 'CRC', 'currency' => 'Costa Rican Colon', 'minorUnit' => 2, 'numericCode' => 188, ), 'CUP' => array ( 'alphabeticCode' => 'CUP', 'currency' => 'Cuban Peso', 'minorUnit' => 2, 'numericCode' => 192, ), 'CVE' => array ( 'alphabeticCode' => 'CVE', 'currency' => 'Cabo Verde Escudo', 'minorUnit' => 2, 'numericCode' => 132, ), 'CZK' => array ( 'alphabeticCode' => 'CZK', 'currency' => 'Czech Koruna', 'minorUnit' => 2, 'numericCode' => 203, ), 'DJF' => array ( 'alphabeticCode' => 'DJF', 'currency' => 'Djibouti Franc', 'minorUnit' => 0, 'numericCode' => 262, ), 'DKK' => array ( 'alphabeticCode' => 'DKK', 'currency' => 'Danish Krone', 'minorUnit' => 2, 'numericCode' => 208, ), 'DOP' => array ( 'alphabeticCode' => 'DOP', 'currency' => 'Dominican Peso', 'minorUnit' => 2, 'numericCode' => 214, ), 'DZD' => array ( 'alphabeticCode' => 'DZD', 'currency' => 'Algerian Dinar', 'minorUnit' => 2, 'numericCode' => 12, ), 'EGP' => array ( 'alphabeticCode' => 'EGP', 'currency' => 'Egyptian Pound', 'minorUnit' => 2, 'numericCode' => 818, ), 'ERN' => array ( 'alphabeticCode' => 'ERN', 'currency' => 'Nakfa', 'minorUnit' => 2, 'numericCode' => 232, ), 'ETB' => array ( 'alphabeticCode' => 'ETB', 'currency' => 'Ethiopian Birr', 'minorUnit' => 2, 'numericCode' => 230, ), 'EUR' => array ( 'alphabeticCode' => 'EUR', 'currency' => 'Euro', 'minorUnit' => 2, 'numericCode' => 978, ), 'FJD' => array ( 'alphabeticCode' => 'FJD', 'currency' => 'Fiji Dollar', 'minorUnit' => 2, 'numericCode' => 242, ), 'FKP' => array ( 'alphabeticCode' => 'FKP', 'currency' => 'Falkland Islands Pound', 'minorUnit' => 2, 'numericCode' => 238, ), 'GBP' => array ( 'alphabeticCode' => 'GBP', 'currency' => 'Pound Sterling', 'minorUnit' => 2, 'numericCode' => 826, ), 'GEL' => array ( 'alphabeticCode' => 'GEL', 'currency' => 'Lari', 'minorUnit' => 2, 'numericCode' => 981, ), 'GHS' => array ( 'alphabeticCode' => 'GHS', 'currency' => 'Ghana Cedi', 'minorUnit' => 2, 'numericCode' => 936, ), 'GIP' => array ( 'alphabeticCode' => 'GIP', 'currency' => 'Gibraltar Pound', 'minorUnit' => 2, 'numericCode' => 292, ), 'GMD' => array ( 'alphabeticCode' => 'GMD', 'currency' => 'Dalasi', 'minorUnit' => 2, 'numericCode' => 270, ), 'GNF' => array ( 'alphabeticCode' => 'GNF', 'currency' => 'Guinean Franc', 'minorUnit' => 0, 'numericCode' => 324, ), 'GTQ' => array ( 'alphabeticCode' => 'GTQ', 'currency' => 'Quetzal', 'minorUnit' => 2, 'numericCode' => 320, ), 'GYD' => array ( 'alphabeticCode' => 'GYD', 'currency' => 'Guyana Dollar', 'minorUnit' => 2, 'numericCode' => 328, ), 'HKD' => array ( 'alphabeticCode' => 'HKD', 'currency' => 'Hong Kong Dollar', 'minorUnit' => 2, 'numericCode' => 344, ), 'HNL' => array ( 'alphabeticCode' => 'HNL', 'currency' => 'Lempira', 'minorUnit' => 2, 'numericCode' => 340, ), 'HTG' => array ( 'alphabeticCode' => 'HTG', 'currency' => 'Gourde', 'minorUnit' => 2, 'numericCode' => 332, ), 'HUF' => array ( 'alphabeticCode' => 'HUF', 'currency' => 'Forint', 'minorUnit' => 2, 'numericCode' => 348, ), 'IDR' => array ( 'alphabeticCode' => 'IDR', 'currency' => 'Rupiah', 'minorUnit' => 2, 'numericCode' => 360, ), 'ILS' => array ( 'alphabeticCode' => 'ILS', 'currency' => 'New Israeli Sheqel', 'minorUnit' => 2, 'numericCode' => 376, ), 'INR' => array ( 'alphabeticCode' => 'INR', 'currency' => 'Indian Rupee', 'minorUnit' => 2, 'numericCode' => 356, ), 'IQD' => array ( 'alphabeticCode' => 'IQD', 'currency' => 'Iraqi Dinar', 'minorUnit' => 3, 'numericCode' => 368, ), 'IRR' => array ( 'alphabeticCode' => 'IRR', 'currency' => 'Iranian Rial', 'minorUnit' => 2, 'numericCode' => 364, ), 'ISK' => array ( 'alphabeticCode' => 'ISK', 'currency' => 'Iceland Krona', 'minorUnit' => 0, 'numericCode' => 352, ), 'JMD' => array ( 'alphabeticCode' => 'JMD', 'currency' => 'Jamaican Dollar', 'minorUnit' => 2, 'numericCode' => 388, ), 'JOD' => array ( 'alphabeticCode' => 'JOD', 'currency' => 'Jordanian Dinar', 'minorUnit' => 3, 'numericCode' => 400, ), 'JPY' => array ( 'alphabeticCode' => 'JPY', 'currency' => 'Yen', 'minorUnit' => 0, 'numericCode' => 392, ), 'KES' => array ( 'alphabeticCode' => 'KES', 'currency' => 'Kenyan Shilling', 'minorUnit' => 2, 'numericCode' => 404, ), 'KGS' => array ( 'alphabeticCode' => 'KGS', 'currency' => 'Som', 'minorUnit' => 2, 'numericCode' => 417, ), 'KHR' => array ( 'alphabeticCode' => 'KHR', 'currency' => 'Riel', 'minorUnit' => 2, 'numericCode' => 116, ), 'KMF' => array ( 'alphabeticCode' => 'KMF', 'currency' => 'Comorian Franc ', 'minorUnit' => 0, 'numericCode' => 174, ), 'KPW' => array ( 'alphabeticCode' => 'KPW', 'currency' => 'North Korean Won', 'minorUnit' => 2, 'numericCode' => 408, ), 'KRW' => array ( 'alphabeticCode' => 'KRW', 'currency' => 'Won', 'minorUnit' => 0, 'numericCode' => 410, ), 'KWD' => array ( 'alphabeticCode' => 'KWD', 'currency' => 'Kuwaiti Dinar', 'minorUnit' => 3, 'numericCode' => 414, ), 'KYD' => array ( 'alphabeticCode' => 'KYD', 'currency' => 'Cayman Islands Dollar', 'minorUnit' => 2, 'numericCode' => 136, ), 'KZT' => array ( 'alphabeticCode' => 'KZT', 'currency' => 'Tenge', 'minorUnit' => 2, 'numericCode' => 398, ), 'LAK' => array ( 'alphabeticCode' => 'LAK', 'currency' => 'Lao Kip', 'minorUnit' => 2, 'numericCode' => 418, ), 'LBP' => array ( 'alphabeticCode' => 'LBP', 'currency' => 'Lebanese Pound', 'minorUnit' => 2, 'numericCode' => 422, ), 'LKR' => array ( 'alphabeticCode' => 'LKR', 'currency' => 'Sri Lanka Rupee', 'minorUnit' => 2, 'numericCode' => 144, ), 'LRD' => array ( 'alphabeticCode' => 'LRD', 'currency' => 'Liberian Dollar', 'minorUnit' => 2, 'numericCode' => 430, ), 'LSL' => array ( 'alphabeticCode' => 'LSL', 'currency' => 'Loti', 'minorUnit' => 2, 'numericCode' => 426, ), 'LYD' => array ( 'alphabeticCode' => 'LYD', 'currency' => 'Libyan Dinar', 'minorUnit' => 3, 'numericCode' => 434, ), 'MAD' => array ( 'alphabeticCode' => 'MAD', 'currency' => 'Moroccan Dirham', 'minorUnit' => 2, 'numericCode' => 504, ), 'MDL' => array ( 'alphabeticCode' => 'MDL', 'currency' => 'Moldovan Leu', 'minorUnit' => 2, 'numericCode' => 498, ), 'MGA' => array ( 'alphabeticCode' => 'MGA', 'currency' => 'Malagasy Ariary', 'minorUnit' => 2, 'numericCode' => 969, ), 'MKD' => array ( 'alphabeticCode' => 'MKD', 'currency' => 'Denar', 'minorUnit' => 2, 'numericCode' => 807, ), 'MMK' => array ( 'alphabeticCode' => 'MMK', 'currency' => 'Kyat', 'minorUnit' => 2, 'numericCode' => 104, ), 'MNT' => array ( 'alphabeticCode' => 'MNT', 'currency' => 'Tugrik', 'minorUnit' => 2, 'numericCode' => 496, ), 'MOP' => array ( 'alphabeticCode' => 'MOP', 'currency' => 'Pataca', 'minorUnit' => 2, 'numericCode' => 446, ), 'MRU' => array ( 'alphabeticCode' => 'MRU', 'currency' => 'Ouguiya', 'minorUnit' => 2, 'numericCode' => 929, ), 'MUR' => array ( 'alphabeticCode' => 'MUR', 'currency' => 'Mauritius Rupee', 'minorUnit' => 2, 'numericCode' => 480, ), 'MVR' => array ( 'alphabeticCode' => 'MVR', 'currency' => 'Rufiyaa', 'minorUnit' => 2, 'numericCode' => 462, ), 'MWK' => array ( 'alphabeticCode' => 'MWK', 'currency' => 'Malawi Kwacha', 'minorUnit' => 2, 'numericCode' => 454, ), 'MXN' => array ( 'alphabeticCode' => 'MXN', 'currency' => 'Mexican Peso', 'minorUnit' => 2, 'numericCode' => 484, ), 'MXV' => array ( 'alphabeticCode' => 'MXV', 'currency' => 'Mexican Unidad de Inversion (UDI)', 'minorUnit' => 2, 'numericCode' => 979, ), 'MYR' => array ( 'alphabeticCode' => 'MYR', 'currency' => 'Malaysian Ringgit', 'minorUnit' => 2, 'numericCode' => 458, ), 'MZN' => array ( 'alphabeticCode' => 'MZN', 'currency' => 'Mozambique Metical', 'minorUnit' => 2, 'numericCode' => 943, ), 'NAD' => array ( 'alphabeticCode' => 'NAD', 'currency' => 'Namibia Dollar', 'minorUnit' => 2, 'numericCode' => 516, ), 'NGN' => array ( 'alphabeticCode' => 'NGN', 'currency' => 'Naira', 'minorUnit' => 2, 'numericCode' => 566, ), 'NIO' => array ( 'alphabeticCode' => 'NIO', 'currency' => 'Cordoba Oro', 'minorUnit' => 2, 'numericCode' => 558, ), 'NOK' => array ( 'alphabeticCode' => 'NOK', 'currency' => 'Norwegian Krone', 'minorUnit' => 2, 'numericCode' => 578, ), 'NPR' => array ( 'alphabeticCode' => 'NPR', 'currency' => 'Nepalese Rupee', 'minorUnit' => 2, 'numericCode' => 524, ), 'NZD' => array ( 'alphabeticCode' => 'NZD', 'currency' => 'New Zealand Dollar', 'minorUnit' => 2, 'numericCode' => 554, ), 'OMR' => array ( 'alphabeticCode' => 'OMR', 'currency' => 'Rial Omani', 'minorUnit' => 3, 'numericCode' => 512, ), 'PAB' => array ( 'alphabeticCode' => 'PAB', 'currency' => 'Balboa', 'minorUnit' => 2, 'numericCode' => 590, ), 'PEN' => array ( 'alphabeticCode' => 'PEN', 'currency' => 'Sol', 'minorUnit' => 2, 'numericCode' => 604, ), 'PGK' => array ( 'alphabeticCode' => 'PGK', 'currency' => 'Kina', 'minorUnit' => 2, 'numericCode' => 598, ), 'PHP' => array ( 'alphabeticCode' => 'PHP', 'currency' => 'Philippine Peso', 'minorUnit' => 2, 'numericCode' => 608, ), 'PKR' => array ( 'alphabeticCode' => 'PKR', 'currency' => 'Pakistan Rupee', 'minorUnit' => 2, 'numericCode' => 586, ), 'PLN' => array ( 'alphabeticCode' => 'PLN', 'currency' => 'Zloty', 'minorUnit' => 2, 'numericCode' => 985, ), 'PYG' => array ( 'alphabeticCode' => 'PYG', 'currency' => 'Guarani', 'minorUnit' => 0, 'numericCode' => 600, ), 'QAR' => array ( 'alphabeticCode' => 'QAR', 'currency' => 'Qatari Rial', 'minorUnit' => 2, 'numericCode' => 634, ), 'RON' => array ( 'alphabeticCode' => 'RON', 'currency' => 'Romanian Leu', 'minorUnit' => 2, 'numericCode' => 946, ), 'RSD' => array ( 'alphabeticCode' => 'RSD', 'currency' => 'Serbian Dinar', 'minorUnit' => 2, 'numericCode' => 941, ), 'RUB' => array ( 'alphabeticCode' => 'RUB', 'currency' => 'Russian Ruble', 'minorUnit' => 2, 'numericCode' => 643, ), 'RWF' => array ( 'alphabeticCode' => 'RWF', 'currency' => 'Rwanda Franc', 'minorUnit' => 0, 'numericCode' => 646, ), 'SAR' => array ( 'alphabeticCode' => 'SAR', 'currency' => 'Saudi Riyal', 'minorUnit' => 2, 'numericCode' => 682, ), 'SBD' => array ( 'alphabeticCode' => 'SBD', 'currency' => 'Solomon Islands Dollar', 'minorUnit' => 2, 'numericCode' => 90, ), 'SCR' => array ( 'alphabeticCode' => 'SCR', 'currency' => 'Seychelles Rupee', 'minorUnit' => 2, 'numericCode' => 690, ), 'SDG' => array ( 'alphabeticCode' => 'SDG', 'currency' => 'Sudanese Pound', 'minorUnit' => 2, 'numericCode' => 938, ), 'SEK' => array ( 'alphabeticCode' => 'SEK', 'currency' => 'Swedish Krona', 'minorUnit' => 2, 'numericCode' => 752, ), 'SGD' => array ( 'alphabeticCode' => 'SGD', 'currency' => 'Singapore Dollar', 'minorUnit' => 2, 'numericCode' => 702, ), 'SHP' => array ( 'alphabeticCode' => 'SHP', 'currency' => 'Saint Helena Pound', 'minorUnit' => 2, 'numericCode' => 654, ), 'SLE' => array ( 'alphabeticCode' => 'SLE', 'currency' => 'Leone', 'minorUnit' => 2, 'numericCode' => 925, ), 'SOS' => array ( 'alphabeticCode' => 'SOS', 'currency' => 'Somali Shilling', 'minorUnit' => 2, 'numericCode' => 706, ), 'SRD' => array ( 'alphabeticCode' => 'SRD', 'currency' => 'Surinam Dollar', 'minorUnit' => 2, 'numericCode' => 968, ), 'SSP' => array ( 'alphabeticCode' => 'SSP', 'currency' => 'South Sudanese Pound', 'minorUnit' => 2, 'numericCode' => 728, ), 'STN' => array ( 'alphabeticCode' => 'STN', 'currency' => 'Dobra', 'minorUnit' => 2, 'numericCode' => 930, ), 'SVC' => array ( 'alphabeticCode' => 'SVC', 'currency' => 'El Salvador Colon', 'minorUnit' => 2, 'numericCode' => 222, ), 'SYP' => array ( 'alphabeticCode' => 'SYP', 'currency' => 'Syrian Pound', 'minorUnit' => 2, 'numericCode' => 760, ), 'SZL' => array ( 'alphabeticCode' => 'SZL', 'currency' => 'Lilangeni', 'minorUnit' => 2, 'numericCode' => 748, ), 'THB' => array ( 'alphabeticCode' => 'THB', 'currency' => 'Baht', 'minorUnit' => 2, 'numericCode' => 764, ), 'TJS' => array ( 'alphabeticCode' => 'TJS', 'currency' => 'Somoni', 'minorUnit' => 2, 'numericCode' => 972, ), 'TMT' => array ( 'alphabeticCode' => 'TMT', 'currency' => 'Turkmenistan New Manat', 'minorUnit' => 2, 'numericCode' => 934, ), 'TND' => array ( 'alphabeticCode' => 'TND', 'currency' => 'Tunisian Dinar', 'minorUnit' => 3, 'numericCode' => 788, ), 'TOP' => array ( 'alphabeticCode' => 'TOP', 'currency' => 'Pa’anga', 'minorUnit' => 2, 'numericCode' => 776, ), 'TRY' => array ( 'alphabeticCode' => 'TRY', 'currency' => 'Turkish Lira', 'minorUnit' => 2, 'numericCode' => 949, ), 'TTD' => array ( 'alphabeticCode' => 'TTD', 'currency' => 'Trinidad and Tobago Dollar', 'minorUnit' => 2, 'numericCode' => 780, ), 'TWD' => array ( 'alphabeticCode' => 'TWD', 'currency' => 'New Taiwan Dollar', 'minorUnit' => 2, 'numericCode' => 901, ), 'TZS' => array ( 'alphabeticCode' => 'TZS', 'currency' => 'Tanzanian Shilling', 'minorUnit' => 2, 'numericCode' => 834, ), 'UAH' => array ( 'alphabeticCode' => 'UAH', 'currency' => 'Hryvnia', 'minorUnit' => 2, 'numericCode' => 980, ), 'UGX' => array ( 'alphabeticCode' => 'UGX', 'currency' => 'Uganda Shilling', 'minorUnit' => 0, 'numericCode' => 800, ), 'USD' => array ( 'alphabeticCode' => 'USD', 'currency' => 'US Dollar', 'minorUnit' => 2, 'numericCode' => 840, ), 'USN' => array ( 'alphabeticCode' => 'USN', 'currency' => 'US Dollar (Next day)', 'minorUnit' => 2, 'numericCode' => 997, ), 'UYI' => array ( 'alphabeticCode' => 'UYI', 'currency' => 'Uruguay Peso en Unidades Indexadas (UI)', 'minorUnit' => 0, 'numericCode' => 940, ), 'UYU' => array ( 'alphabeticCode' => 'UYU', 'currency' => 'Peso Uruguayo', 'minorUnit' => 2, 'numericCode' => 858, ), 'UYW' => array ( 'alphabeticCode' => 'UYW', 'currency' => 'Unidad Previsional', 'minorUnit' => 4, 'numericCode' => 927, ), 'UZS' => array ( 'alphabeticCode' => 'UZS', 'currency' => 'Uzbekistan Sum', 'minorUnit' => 2, 'numericCode' => 860, ), 'VED' => array ( 'alphabeticCode' => 'VED', 'currency' => 'Bolívar Soberano', 'minorUnit' => 2, 'numericCode' => 926, ), 'VES' => array ( 'alphabeticCode' => 'VES', 'currency' => 'Bolívar Soberano', 'minorUnit' => 2, 'numericCode' => 928, ), 'VND' => array ( 'alphabeticCode' => 'VND', 'currency' => 'Dong', 'minorUnit' => 0, 'numericCode' => 704, ), 'VUV' => array ( 'alphabeticCode' => 'VUV', 'currency' => 'Vatu', 'minorUnit' => 0, 'numericCode' => 548, ), 'WST' => array ( 'alphabeticCode' => 'WST', 'currency' => 'Tala', 'minorUnit' => 2, 'numericCode' => 882, ), 'XAD' => array ( 'alphabeticCode' => 'XAD', 'currency' => 'Arab Accounting Dinar', 'minorUnit' => 2, 'numericCode' => 396, ), 'XAF' => array ( 'alphabeticCode' => 'XAF', 'currency' => 'CFA Franc BEAC', 'minorUnit' => 0, 'numericCode' => 950, ), 'XAG' => array ( 'alphabeticCode' => 'XAG', 'currency' => 'Silver', 'minorUnit' => 0, 'numericCode' => 961, ), 'XAU' => array ( 'alphabeticCode' => 'XAU', 'currency' => 'Gold', 'minorUnit' => 0, 'numericCode' => 959, ), 'XBA' => array ( 'alphabeticCode' => 'XBA', 'currency' => 'Bond Markets Unit European Composite Unit (EURCO)', 'minorUnit' => 0, 'numericCode' => 955, ), 'XBB' => array ( 'alphabeticCode' => 'XBB', 'currency' => 'Bond Markets Unit European Monetary Unit (E.M.U.-6)', 'minorUnit' => 0, 'numericCode' => 956, ), 'XBC' => array ( 'alphabeticCode' => 'XBC', 'currency' => 'Bond Markets Unit European Unit of Account 9 (E.U.A.-9)', 'minorUnit' => 0, 'numericCode' => 957, ), 'XBD' => array ( 'alphabeticCode' => 'XBD', 'currency' => 'Bond Markets Unit European Unit of Account 17 (E.U.A.-17)', 'minorUnit' => 0, 'numericCode' => 958, ), 'XCD' => array ( 'alphabeticCode' => 'XCD', 'currency' => 'East Caribbean Dollar', 'minorUnit' => 2, 'numericCode' => 951, ), 'XCG' => array ( 'alphabeticCode' => 'XCG', 'currency' => 'Caribbean Guilder', 'minorUnit' => 2, 'numericCode' => 532, ), 'XDR' => array ( 'alphabeticCode' => 'XDR', 'currency' => 'SDR (Special Drawing Right)', 'minorUnit' => 0, 'numericCode' => 960, ), 'XOF' => array ( 'alphabeticCode' => 'XOF', 'currency' => 'CFA Franc BCEAO', 'minorUnit' => 0, 'numericCode' => 952, ), 'XPD' => array ( 'alphabeticCode' => 'XPD', 'currency' => 'Palladium', 'minorUnit' => 0, 'numericCode' => 964, ), 'XPF' => array ( 'alphabeticCode' => 'XPF', 'currency' => 'CFP Franc', 'minorUnit' => 0, 'numericCode' => 953, ), 'XPT' => array ( 'alphabeticCode' => 'XPT', 'currency' => 'Platinum', 'minorUnit' => 0, 'numericCode' => 962, ), 'XSU' => array ( 'alphabeticCode' => 'XSU', 'currency' => 'Sucre', 'minorUnit' => 0, 'numericCode' => 994, ), 'XTS' => array ( 'alphabeticCode' => 'XTS', 'currency' => 'Codes specifically reserved for testing purposes', 'minorUnit' => 0, 'numericCode' => 963, ), 'XUA' => array ( 'alphabeticCode' => 'XUA', 'currency' => 'ADB Unit of Account', 'minorUnit' => 0, 'numericCode' => 965, ), 'XXX' => array ( 'alphabeticCode' => 'XXX', 'currency' => 'The codes assigned for transactions where no currency is involved', 'minorUnit' => 0, 'numericCode' => 999, ), 'YER' => array ( 'alphabeticCode' => 'YER', 'currency' => 'Yemeni Rial', 'minorUnit' => 2, 'numericCode' => 886, ), 'ZAR' => array ( 'alphabeticCode' => 'ZAR', 'currency' => 'Rand', 'minorUnit' => 2, 'numericCode' => 710, ), 'ZMW' => array ( 'alphabeticCode' => 'ZMW', 'currency' => 'Zambian Kwacha', 'minorUnit' => 2, 'numericCode' => 967, ), 'ZWG' => array ( 'alphabeticCode' => 'ZWG', 'currency' => 'Zimbabwe Gold', 'minorUnit' => 2, 'numericCode' => 924, ), );PK[$W]a؈Ãoo$resources/generate-money-factory.phpnu„[µü¤ * $fiveDollar = Money::USD(500); * * * @param non-empty-string $method * @param array{numeric-string|int} $arguments * * @throws InvalidArgumentException If amount is not integer(ish). * * @psalm-pure */ public static function __callStatic(string $method, array $arguments): Money { return new Money($arguments[0], new Currency($method)); } } PHP; $methodBuffer = ''; $iterator = new Currencies\AggregateCurrencies([ new Currencies\ISOCurrencies(), new Currencies\BitcoinCurrencies(), new Currencies\CryptoCurrencies(), ]); $currencies = array_unique([...$iterator]); usort($currencies, static fn (Currency $a, Currency $b): int => strcmp($a->getCode(), $b->getCode())); /** @var Currency[] $currencies */ foreach ($currencies as $currency) { $code = $currency->getCode(); if (is_numeric($code[0])) { preg_match('/^([0-9]*)(.*?)$/', $code, $extracted); $formatter = new \NumberFormatter('en', \NumberFormatter::SPELLOUT); $code = strtoupper(preg_replace('/\s+/', '', $formatter->format($extracted[1])) . $extracted[2]); } $methodBuffer .= sprintf(" * @method static Money %s(numeric-string|int \$amount)\n", $code); } $buffer = str_replace('PHPDOC', rtrim($methodBuffer), $buffer); file_put_contents(__DIR__.'/../src/MoneyFactory.php', $buffer); })(); PK[$W]*nPå´ ´ %resources/generate-teller-factory.phpnu„[µü¤ * $teller = Teller::USD(); * * * @param non-empty-string $method * @param array{0?: Money::ROUND_*} $arguments */ public static function __callStatic(string $method, array $arguments): Teller { $currency = new Currency($method); $currencies = new ISOCurrencies(); $parser = new DecimalMoneyParser($currencies); $formatter = new DecimalMoneyFormatter($currencies); $roundingMode = empty($arguments) ? Money::ROUND_HALF_UP : (int) array_shift($arguments); return new Teller( $currency, $parser, $formatter, $roundingMode ); } } PHP; $methodBuffer = ''; $iterator = new Currencies\AggregateCurrencies([ new Currencies\ISOCurrencies(), new Currencies\BitcoinCurrencies(), new Currencies\CryptoCurrencies(), ]); $currencies = array_unique([...$iterator]); usort($currencies, static fn (Currency $a, Currency $b): int => strcmp($a->getCode(), $b->getCode())); /** @var Currency[] $currencies */ foreach ($currencies as $currency) { $code = $currency->getCode(); if (is_numeric($code[0])) { preg_match('/^([0-9]*)(.*?)$/', $code, $extracted); $formatter = new \NumberFormatter('en', \NumberFormatter::SPELLOUT); $code = strtoupper(preg_replace('/\s+/', '', $formatter->format($extracted[1])) . $extracted[2]); } $methodBuffer .= sprintf(" * @method static Teller %s(int \$roundingMode = Money::ROUND_HALF_UP)\n", $code); } $buffer = str_replace('PHPDOC', rtrim($methodBuffer), $buffer); file_put_contents(__DIR__.'/../src/TellerFactory.php', $buffer); })(); PK[$W]µþe!u!uresources/binance.phpnu„[µü¤ array ( 'symbol' => '1000CAT', 'minorUnit' => 8, ), '1000CHEEMS' => array ( 'symbol' => '1000CHEEMS', 'minorUnit' => 8, ), '1000SATS' => array ( 'symbol' => '1000SATS', 'minorUnit' => 8, ), '1INCH' => array ( 'symbol' => '1INCH', 'minorUnit' => 8, ), '1MBABYDOGE' => array ( 'symbol' => '1MBABYDOGE', 'minorUnit' => 8, ), 'A' => array ( 'symbol' => 'A', 'minorUnit' => 8, ), 'AAVE' => array ( 'symbol' => 'AAVE', 'minorUnit' => 8, ), 'ACA' => array ( 'symbol' => 'ACA', 'minorUnit' => 8, ), 'ACE' => array ( 'symbol' => 'ACE', 'minorUnit' => 8, ), 'ACH' => array ( 'symbol' => 'ACH', 'minorUnit' => 8, ), 'ACM' => array ( 'symbol' => 'ACM', 'minorUnit' => 8, ), 'ACT' => array ( 'symbol' => 'ACT', 'minorUnit' => 8, ), 'ACX' => array ( 'symbol' => 'ACX', 'minorUnit' => 8, ), 'ADA' => array ( 'symbol' => 'ADA', 'minorUnit' => 8, ), 'ADX' => array ( 'symbol' => 'ADX', 'minorUnit' => 8, ), 'AEUR' => array ( 'symbol' => 'AEUR', 'minorUnit' => 8, ), 'AEVO' => array ( 'symbol' => 'AEVO', 'minorUnit' => 8, ), 'AGLD' => array ( 'symbol' => 'AGLD', 'minorUnit' => 8, ), 'AI' => array ( 'symbol' => 'AI', 'minorUnit' => 8, ), 'AIXBT' => array ( 'symbol' => 'AIXBT', 'minorUnit' => 8, ), 'ALCX' => array ( 'symbol' => 'ALCX', 'minorUnit' => 8, ), 'ALGO' => array ( 'symbol' => 'ALGO', 'minorUnit' => 8, ), 'ALICE' => array ( 'symbol' => 'ALICE', 'minorUnit' => 8, ), 'ALPHA' => array ( 'symbol' => 'ALPHA', 'minorUnit' => 8, ), 'ALPINE' => array ( 'symbol' => 'ALPINE', 'minorUnit' => 8, ), 'ALT' => array ( 'symbol' => 'ALT', 'minorUnit' => 8, ), 'AMP' => array ( 'symbol' => 'AMP', 'minorUnit' => 8, ), 'ANIME' => array ( 'symbol' => 'ANIME', 'minorUnit' => 8, ), 'ANKR' => array ( 'symbol' => 'ANKR', 'minorUnit' => 8, ), 'APE' => array ( 'symbol' => 'APE', 'minorUnit' => 8, ), 'API3' => array ( 'symbol' => 'API3', 'minorUnit' => 8, ), 'APT' => array ( 'symbol' => 'APT', 'minorUnit' => 8, ), 'AR' => array ( 'symbol' => 'AR', 'minorUnit' => 8, ), 'ARB' => array ( 'symbol' => 'ARB', 'minorUnit' => 8, ), 'ARDR' => array ( 'symbol' => 'ARDR', 'minorUnit' => 8, ), 'ARK' => array ( 'symbol' => 'ARK', 'minorUnit' => 8, ), 'ARKM' => array ( 'symbol' => 'ARKM', 'minorUnit' => 8, ), 'ARPA' => array ( 'symbol' => 'ARPA', 'minorUnit' => 8, ), 'ARS' => array ( 'symbol' => 'ARS', 'minorUnit' => 8, ), 'ASR' => array ( 'symbol' => 'ASR', 'minorUnit' => 8, ), 'ASTR' => array ( 'symbol' => 'ASTR', 'minorUnit' => 8, ), 'ATA' => array ( 'symbol' => 'ATA', 'minorUnit' => 8, ), 'ATM' => array ( 'symbol' => 'ATM', 'minorUnit' => 8, ), 'ATOM' => array ( 'symbol' => 'ATOM', 'minorUnit' => 8, ), 'AUCTION' => array ( 'symbol' => 'AUCTION', 'minorUnit' => 8, ), 'AUDIO' => array ( 'symbol' => 'AUDIO', 'minorUnit' => 8, ), 'AVA' => array ( 'symbol' => 'AVA', 'minorUnit' => 8, ), 'AVAX' => array ( 'symbol' => 'AVAX', 'minorUnit' => 8, ), 'AWE' => array ( 'symbol' => 'AWE', 'minorUnit' => 8, ), 'AXL' => array ( 'symbol' => 'AXL', 'minorUnit' => 8, ), 'AXS' => array ( 'symbol' => 'AXS', 'minorUnit' => 8, ), 'BABY' => array ( 'symbol' => 'BABY', 'minorUnit' => 8, ), 'BAKE' => array ( 'symbol' => 'BAKE', 'minorUnit' => 8, ), 'BANANA' => array ( 'symbol' => 'BANANA', 'minorUnit' => 8, ), 'BANANAS31' => array ( 'symbol' => 'BANANAS31', 'minorUnit' => 8, ), 'BAND' => array ( 'symbol' => 'BAND', 'minorUnit' => 8, ), 'BAR' => array ( 'symbol' => 'BAR', 'minorUnit' => 8, ), 'BAT' => array ( 'symbol' => 'BAT', 'minorUnit' => 8, ), 'BB' => array ( 'symbol' => 'BB', 'minorUnit' => 8, ), 'BCH' => array ( 'symbol' => 'BCH', 'minorUnit' => 8, ), 'BEAMX' => array ( 'symbol' => 'BEAMX', 'minorUnit' => 8, ), 'BEL' => array ( 'symbol' => 'BEL', 'minorUnit' => 8, ), 'BERA' => array ( 'symbol' => 'BERA', 'minorUnit' => 8, ), 'BICO' => array ( 'symbol' => 'BICO', 'minorUnit' => 8, ), 'BIFI' => array ( 'symbol' => 'BIFI', 'minorUnit' => 8, ), 'BIGTIME' => array ( 'symbol' => 'BIGTIME', 'minorUnit' => 8, ), 'BIO' => array ( 'symbol' => 'BIO', 'minorUnit' => 8, ), 'BLUR' => array ( 'symbol' => 'BLUR', 'minorUnit' => 8, ), 'BMT' => array ( 'symbol' => 'BMT', 'minorUnit' => 8, ), 'BNB' => array ( 'symbol' => 'BNB', 'minorUnit' => 8, ), 'BNSOL' => array ( 'symbol' => 'BNSOL', 'minorUnit' => 8, ), 'BNT' => array ( 'symbol' => 'BNT', 'minorUnit' => 8, ), 'BOME' => array ( 'symbol' => 'BOME', 'minorUnit' => 8, ), 'BONK' => array ( 'symbol' => 'BONK', 'minorUnit' => 8, ), 'BROCCOLI714' => array ( 'symbol' => 'BROCCOLI714', 'minorUnit' => 8, ), 'BSW' => array ( 'symbol' => 'BSW', 'minorUnit' => 8, ), 'BTC' => array ( 'symbol' => 'BTC', 'minorUnit' => 8, ), 'BTTC' => array ( 'symbol' => 'BTTC', 'minorUnit' => 8, ), 'C98' => array ( 'symbol' => 'C98', 'minorUnit' => 8, ), 'CAKE' => array ( 'symbol' => 'CAKE', 'minorUnit' => 8, ), 'CATI' => array ( 'symbol' => 'CATI', 'minorUnit' => 8, ), 'CELO' => array ( 'symbol' => 'CELO', 'minorUnit' => 8, ), 'CELR' => array ( 'symbol' => 'CELR', 'minorUnit' => 8, ), 'CETUS' => array ( 'symbol' => 'CETUS', 'minorUnit' => 8, ), 'CFX' => array ( 'symbol' => 'CFX', 'minorUnit' => 8, ), 'CGPT' => array ( 'symbol' => 'CGPT', 'minorUnit' => 8, ), 'CHESS' => array ( 'symbol' => 'CHESS', 'minorUnit' => 8, ), 'CHR' => array ( 'symbol' => 'CHR', 'minorUnit' => 8, ), 'CHZ' => array ( 'symbol' => 'CHZ', 'minorUnit' => 8, ), 'CITY' => array ( 'symbol' => 'CITY', 'minorUnit' => 8, ), 'CKB' => array ( 'symbol' => 'CKB', 'minorUnit' => 8, ), 'COMP' => array ( 'symbol' => 'COMP', 'minorUnit' => 8, ), 'COOKIE' => array ( 'symbol' => 'COOKIE', 'minorUnit' => 8, ), 'COP' => array ( 'symbol' => 'COP', 'minorUnit' => 8, ), 'COS' => array ( 'symbol' => 'COS', 'minorUnit' => 8, ), 'COTI' => array ( 'symbol' => 'COTI', 'minorUnit' => 8, ), 'COW' => array ( 'symbol' => 'COW', 'minorUnit' => 8, ), 'CRV' => array ( 'symbol' => 'CRV', 'minorUnit' => 8, ), 'CTK' => array ( 'symbol' => 'CTK', 'minorUnit' => 8, ), 'CTSI' => array ( 'symbol' => 'CTSI', 'minorUnit' => 8, ), 'CVC' => array ( 'symbol' => 'CVC', 'minorUnit' => 8, ), 'CVX' => array ( 'symbol' => 'CVX', 'minorUnit' => 8, ), 'CYBER' => array ( 'symbol' => 'CYBER', 'minorUnit' => 8, ), 'CZK' => array ( 'symbol' => 'CZK', 'minorUnit' => 8, ), 'D' => array ( 'symbol' => 'D', 'minorUnit' => 8, ), 'DAI' => array ( 'symbol' => 'DAI', 'minorUnit' => 8, ), 'DASH' => array ( 'symbol' => 'DASH', 'minorUnit' => 8, ), 'DATA' => array ( 'symbol' => 'DATA', 'minorUnit' => 8, ), 'DCR' => array ( 'symbol' => 'DCR', 'minorUnit' => 8, ), 'DEGO' => array ( 'symbol' => 'DEGO', 'minorUnit' => 8, ), 'DENT' => array ( 'symbol' => 'DENT', 'minorUnit' => 8, ), 'DEXE' => array ( 'symbol' => 'DEXE', 'minorUnit' => 8, ), 'DF' => array ( 'symbol' => 'DF', 'minorUnit' => 8, ), 'DGB' => array ( 'symbol' => 'DGB', 'minorUnit' => 8, ), 'DIA' => array ( 'symbol' => 'DIA', 'minorUnit' => 8, ), 'DODO' => array ( 'symbol' => 'DODO', 'minorUnit' => 8, ), 'DOGE' => array ( 'symbol' => 'DOGE', 'minorUnit' => 8, ), 'DOGS' => array ( 'symbol' => 'DOGS', 'minorUnit' => 8, ), 'DOT' => array ( 'symbol' => 'DOT', 'minorUnit' => 8, ), 'DUSK' => array ( 'symbol' => 'DUSK', 'minorUnit' => 8, ), 'DYDX' => array ( 'symbol' => 'DYDX', 'minorUnit' => 8, ), 'DYM' => array ( 'symbol' => 'DYM', 'minorUnit' => 8, ), 'EDU' => array ( 'symbol' => 'EDU', 'minorUnit' => 8, ), 'EGLD' => array ( 'symbol' => 'EGLD', 'minorUnit' => 8, ), 'EIGEN' => array ( 'symbol' => 'EIGEN', 'minorUnit' => 8, ), 'ENA' => array ( 'symbol' => 'ENA', 'minorUnit' => 8, ), 'ENJ' => array ( 'symbol' => 'ENJ', 'minorUnit' => 8, ), 'ENS' => array ( 'symbol' => 'ENS', 'minorUnit' => 8, ), 'EPIC' => array ( 'symbol' => 'EPIC', 'minorUnit' => 8, ), 'ETC' => array ( 'symbol' => 'ETC', 'minorUnit' => 8, ), 'ETH' => array ( 'symbol' => 'ETH', 'minorUnit' => 8, ), 'ETHFI' => array ( 'symbol' => 'ETHFI', 'minorUnit' => 8, ), 'EURI' => array ( 'symbol' => 'EURI', 'minorUnit' => 8, ), 'FARM' => array ( 'symbol' => 'FARM', 'minorUnit' => 8, ), 'FDUSD' => array ( 'symbol' => 'FDUSD', 'minorUnit' => 8, ), 'FET' => array ( 'symbol' => 'FET', 'minorUnit' => 8, ), 'FIDA' => array ( 'symbol' => 'FIDA', 'minorUnit' => 8, ), 'FIL' => array ( 'symbol' => 'FIL', 'minorUnit' => 8, ), 'FIO' => array ( 'symbol' => 'FIO', 'minorUnit' => 8, ), 'FIS' => array ( 'symbol' => 'FIS', 'minorUnit' => 8, ), 'FLM' => array ( 'symbol' => 'FLM', 'minorUnit' => 8, ), 'FLOKI' => array ( 'symbol' => 'FLOKI', 'minorUnit' => 8, ), 'FLOW' => array ( 'symbol' => 'FLOW', 'minorUnit' => 8, ), 'FLUX' => array ( 'symbol' => 'FLUX', 'minorUnit' => 8, ), 'FORM' => array ( 'symbol' => 'FORM', 'minorUnit' => 8, ), 'FORTH' => array ( 'symbol' => 'FORTH', 'minorUnit' => 8, ), 'FTT' => array ( 'symbol' => 'FTT', 'minorUnit' => 8, ), 'FUN' => array ( 'symbol' => 'FUN', 'minorUnit' => 8, ), 'FXS' => array ( 'symbol' => 'FXS', 'minorUnit' => 8, ), 'G' => array ( 'symbol' => 'G', 'minorUnit' => 8, ), 'GALA' => array ( 'symbol' => 'GALA', 'minorUnit' => 8, ), 'GAS' => array ( 'symbol' => 'GAS', 'minorUnit' => 8, ), 'GHST' => array ( 'symbol' => 'GHST', 'minorUnit' => 8, ), 'GLM' => array ( 'symbol' => 'GLM', 'minorUnit' => 8, ), 'GLMR' => array ( 'symbol' => 'GLMR', 'minorUnit' => 8, ), 'GMT' => array ( 'symbol' => 'GMT', 'minorUnit' => 8, ), 'GMX' => array ( 'symbol' => 'GMX', 'minorUnit' => 8, ), 'GNO' => array ( 'symbol' => 'GNO', 'minorUnit' => 8, ), 'GNS' => array ( 'symbol' => 'GNS', 'minorUnit' => 8, ), 'GPS' => array ( 'symbol' => 'GPS', 'minorUnit' => 8, ), 'GRT' => array ( 'symbol' => 'GRT', 'minorUnit' => 8, ), 'GTC' => array ( 'symbol' => 'GTC', 'minorUnit' => 8, ), 'GUN' => array ( 'symbol' => 'GUN', 'minorUnit' => 8, ), 'HAEDAL' => array ( 'symbol' => 'HAEDAL', 'minorUnit' => 8, ), 'HBAR' => array ( 'symbol' => 'HBAR', 'minorUnit' => 8, ), 'HEI' => array ( 'symbol' => 'HEI', 'minorUnit' => 8, ), 'HFT' => array ( 'symbol' => 'HFT', 'minorUnit' => 8, ), 'HIFI' => array ( 'symbol' => 'HIFI', 'minorUnit' => 8, ), 'HIGH' => array ( 'symbol' => 'HIGH', 'minorUnit' => 8, ), 'HIVE' => array ( 'symbol' => 'HIVE', 'minorUnit' => 8, ), 'HMSTR' => array ( 'symbol' => 'HMSTR', 'minorUnit' => 8, ), 'HOOK' => array ( 'symbol' => 'HOOK', 'minorUnit' => 8, ), 'HOT' => array ( 'symbol' => 'HOT', 'minorUnit' => 8, ), 'HUMA' => array ( 'symbol' => 'HUMA', 'minorUnit' => 8, ), 'HYPER' => array ( 'symbol' => 'HYPER', 'minorUnit' => 8, ), 'ICP' => array ( 'symbol' => 'ICP', 'minorUnit' => 8, ), 'ICX' => array ( 'symbol' => 'ICX', 'minorUnit' => 8, ), 'ID' => array ( 'symbol' => 'ID', 'minorUnit' => 8, ), 'IDEX' => array ( 'symbol' => 'IDEX', 'minorUnit' => 8, ), 'ILV' => array ( 'symbol' => 'ILV', 'minorUnit' => 8, ), 'IMX' => array ( 'symbol' => 'IMX', 'minorUnit' => 8, ), 'INIT' => array ( 'symbol' => 'INIT', 'minorUnit' => 8, ), 'INJ' => array ( 'symbol' => 'INJ', 'minorUnit' => 8, ), 'IO' => array ( 'symbol' => 'IO', 'minorUnit' => 8, ), 'IOST' => array ( 'symbol' => 'IOST', 'minorUnit' => 8, ), 'IOTA' => array ( 'symbol' => 'IOTA', 'minorUnit' => 8, ), 'IOTX' => array ( 'symbol' => 'IOTX', 'minorUnit' => 8, ), 'IQ' => array ( 'symbol' => 'IQ', 'minorUnit' => 8, ), 'JASMY' => array ( 'symbol' => 'JASMY', 'minorUnit' => 8, ), 'JOE' => array ( 'symbol' => 'JOE', 'minorUnit' => 8, ), 'JPY' => array ( 'symbol' => 'JPY', 'minorUnit' => 8, ), 'JST' => array ( 'symbol' => 'JST', 'minorUnit' => 8, ), 'JTO' => array ( 'symbol' => 'JTO', 'minorUnit' => 8, ), 'JUP' => array ( 'symbol' => 'JUP', 'minorUnit' => 8, ), 'JUV' => array ( 'symbol' => 'JUV', 'minorUnit' => 8, ), 'KAIA' => array ( 'symbol' => 'KAIA', 'minorUnit' => 8, ), 'KAITO' => array ( 'symbol' => 'KAITO', 'minorUnit' => 8, ), 'KAVA' => array ( 'symbol' => 'KAVA', 'minorUnit' => 8, ), 'KDA' => array ( 'symbol' => 'KDA', 'minorUnit' => 8, ), 'KERNEL' => array ( 'symbol' => 'KERNEL', 'minorUnit' => 8, ), 'KMD' => array ( 'symbol' => 'KMD', 'minorUnit' => 8, ), 'KMNO' => array ( 'symbol' => 'KMNO', 'minorUnit' => 8, ), 'KNC' => array ( 'symbol' => 'KNC', 'minorUnit' => 8, ), 'KSM' => array ( 'symbol' => 'KSM', 'minorUnit' => 8, ), 'LAYER' => array ( 'symbol' => 'LAYER', 'minorUnit' => 8, ), 'LAZIO' => array ( 'symbol' => 'LAZIO', 'minorUnit' => 8, ), 'LDO' => array ( 'symbol' => 'LDO', 'minorUnit' => 8, ), 'LEVER' => array ( 'symbol' => 'LEVER', 'minorUnit' => 8, ), 'LINK' => array ( 'symbol' => 'LINK', 'minorUnit' => 8, ), 'LISTA' => array ( 'symbol' => 'LISTA', 'minorUnit' => 8, ), 'LOKA' => array ( 'symbol' => 'LOKA', 'minorUnit' => 8, ), 'LPT' => array ( 'symbol' => 'LPT', 'minorUnit' => 8, ), 'LQTY' => array ( 'symbol' => 'LQTY', 'minorUnit' => 8, ), 'LRC' => array ( 'symbol' => 'LRC', 'minorUnit' => 8, ), 'LSK' => array ( 'symbol' => 'LSK', 'minorUnit' => 8, ), 'LTC' => array ( 'symbol' => 'LTC', 'minorUnit' => 8, ), 'LTO' => array ( 'symbol' => 'LTO', 'minorUnit' => 8, ), 'LUMIA' => array ( 'symbol' => 'LUMIA', 'minorUnit' => 8, ), 'LUNA' => array ( 'symbol' => 'LUNA', 'minorUnit' => 8, ), 'LUNC' => array ( 'symbol' => 'LUNC', 'minorUnit' => 8, ), 'MAGIC' => array ( 'symbol' => 'MAGIC', 'minorUnit' => 8, ), 'MANA' => array ( 'symbol' => 'MANA', 'minorUnit' => 8, ), 'MANTA' => array ( 'symbol' => 'MANTA', 'minorUnit' => 8, ), 'MASK' => array ( 'symbol' => 'MASK', 'minorUnit' => 8, ), 'MAV' => array ( 'symbol' => 'MAV', 'minorUnit' => 8, ), 'MBL' => array ( 'symbol' => 'MBL', 'minorUnit' => 8, ), 'MBOX' => array ( 'symbol' => 'MBOX', 'minorUnit' => 8, ), 'MDT' => array ( 'symbol' => 'MDT', 'minorUnit' => 8, ), 'ME' => array ( 'symbol' => 'ME', 'minorUnit' => 8, ), 'MEME' => array ( 'symbol' => 'MEME', 'minorUnit' => 8, ), 'METIS' => array ( 'symbol' => 'METIS', 'minorUnit' => 8, ), 'MINA' => array ( 'symbol' => 'MINA', 'minorUnit' => 8, ), 'MKR' => array ( 'symbol' => 'MKR', 'minorUnit' => 8, ), 'MLN' => array ( 'symbol' => 'MLN', 'minorUnit' => 8, ), 'MOVE' => array ( 'symbol' => 'MOVE', 'minorUnit' => 8, ), 'MOVR' => array ( 'symbol' => 'MOVR', 'minorUnit' => 8, ), 'MTL' => array ( 'symbol' => 'MTL', 'minorUnit' => 8, ), 'MUBARAK' => array ( 'symbol' => 'MUBARAK', 'minorUnit' => 8, ), 'MXN' => array ( 'symbol' => 'MXN', 'minorUnit' => 8, ), 'NEAR' => array ( 'symbol' => 'NEAR', 'minorUnit' => 8, ), 'NEIRO' => array ( 'symbol' => 'NEIRO', 'minorUnit' => 8, ), 'NEO' => array ( 'symbol' => 'NEO', 'minorUnit' => 8, ), 'NEXO' => array ( 'symbol' => 'NEXO', 'minorUnit' => 8, ), 'NFP' => array ( 'symbol' => 'NFP', 'minorUnit' => 8, ), 'NIL' => array ( 'symbol' => 'NIL', 'minorUnit' => 8, ), 'NKN' => array ( 'symbol' => 'NKN', 'minorUnit' => 8, ), 'NMR' => array ( 'symbol' => 'NMR', 'minorUnit' => 8, ), 'NOT' => array ( 'symbol' => 'NOT', 'minorUnit' => 8, ), 'NTRN' => array ( 'symbol' => 'NTRN', 'minorUnit' => 8, ), 'NXPC' => array ( 'symbol' => 'NXPC', 'minorUnit' => 8, ), 'OG' => array ( 'symbol' => 'OG', 'minorUnit' => 8, ), 'OGN' => array ( 'symbol' => 'OGN', 'minorUnit' => 8, ), 'OM' => array ( 'symbol' => 'OM', 'minorUnit' => 8, ), 'OMNI' => array ( 'symbol' => 'OMNI', 'minorUnit' => 8, ), 'ONDO' => array ( 'symbol' => 'ONDO', 'minorUnit' => 8, ), 'ONE' => array ( 'symbol' => 'ONE', 'minorUnit' => 8, ), 'ONG' => array ( 'symbol' => 'ONG', 'minorUnit' => 8, ), 'ONT' => array ( 'symbol' => 'ONT', 'minorUnit' => 8, ), 'OP' => array ( 'symbol' => 'OP', 'minorUnit' => 8, ), 'ORCA' => array ( 'symbol' => 'ORCA', 'minorUnit' => 8, ), 'ORDI' => array ( 'symbol' => 'ORDI', 'minorUnit' => 8, ), 'OSMO' => array ( 'symbol' => 'OSMO', 'minorUnit' => 8, ), 'OXT' => array ( 'symbol' => 'OXT', 'minorUnit' => 8, ), 'PARTI' => array ( 'symbol' => 'PARTI', 'minorUnit' => 8, ), 'PAXG' => array ( 'symbol' => 'PAXG', 'minorUnit' => 8, ), 'PENDLE' => array ( 'symbol' => 'PENDLE', 'minorUnit' => 8, ), 'PENGU' => array ( 'symbol' => 'PENGU', 'minorUnit' => 8, ), 'PEOPLE' => array ( 'symbol' => 'PEOPLE', 'minorUnit' => 8, ), 'PEPE' => array ( 'symbol' => 'PEPE', 'minorUnit' => 8, ), 'PERP' => array ( 'symbol' => 'PERP', 'minorUnit' => 8, ), 'PHA' => array ( 'symbol' => 'PHA', 'minorUnit' => 8, ), 'PHB' => array ( 'symbol' => 'PHB', 'minorUnit' => 8, ), 'PIVX' => array ( 'symbol' => 'PIVX', 'minorUnit' => 8, ), 'PIXEL' => array ( 'symbol' => 'PIXEL', 'minorUnit' => 8, ), 'PNUT' => array ( 'symbol' => 'PNUT', 'minorUnit' => 8, ), 'POL' => array ( 'symbol' => 'POL', 'minorUnit' => 8, ), 'POLYX' => array ( 'symbol' => 'POLYX', 'minorUnit' => 8, ), 'POND' => array ( 'symbol' => 'POND', 'minorUnit' => 8, ), 'PORTAL' => array ( 'symbol' => 'PORTAL', 'minorUnit' => 8, ), 'PORTO' => array ( 'symbol' => 'PORTO', 'minorUnit' => 8, ), 'POWR' => array ( 'symbol' => 'POWR', 'minorUnit' => 8, ), 'PROM' => array ( 'symbol' => 'PROM', 'minorUnit' => 8, ), 'PSG' => array ( 'symbol' => 'PSG', 'minorUnit' => 8, ), 'PUNDIX' => array ( 'symbol' => 'PUNDIX', 'minorUnit' => 8, ), 'PYR' => array ( 'symbol' => 'PYR', 'minorUnit' => 8, ), 'PYTH' => array ( 'symbol' => 'PYTH', 'minorUnit' => 8, ), 'QI' => array ( 'symbol' => 'QI', 'minorUnit' => 8, ), 'QKC' => array ( 'symbol' => 'QKC', 'minorUnit' => 8, ), 'QNT' => array ( 'symbol' => 'QNT', 'minorUnit' => 8, ), 'QTUM' => array ( 'symbol' => 'QTUM', 'minorUnit' => 8, ), 'QUICK' => array ( 'symbol' => 'QUICK', 'minorUnit' => 8, ), 'RAD' => array ( 'symbol' => 'RAD', 'minorUnit' => 8, ), 'RARE' => array ( 'symbol' => 'RARE', 'minorUnit' => 8, ), 'RAY' => array ( 'symbol' => 'RAY', 'minorUnit' => 8, ), 'RDNT' => array ( 'symbol' => 'RDNT', 'minorUnit' => 8, ), 'RED' => array ( 'symbol' => 'RED', 'minorUnit' => 8, ), 'REI' => array ( 'symbol' => 'REI', 'minorUnit' => 8, ), 'RENDER' => array ( 'symbol' => 'RENDER', 'minorUnit' => 8, ), 'REQ' => array ( 'symbol' => 'REQ', 'minorUnit' => 8, ), 'REZ' => array ( 'symbol' => 'REZ', 'minorUnit' => 8, ), 'RIF' => array ( 'symbol' => 'RIF', 'minorUnit' => 8, ), 'RLC' => array ( 'symbol' => 'RLC', 'minorUnit' => 8, ), 'RONIN' => array ( 'symbol' => 'RONIN', 'minorUnit' => 8, ), 'ROSE' => array ( 'symbol' => 'ROSE', 'minorUnit' => 8, ), 'RPL' => array ( 'symbol' => 'RPL', 'minorUnit' => 8, ), 'RSR' => array ( 'symbol' => 'RSR', 'minorUnit' => 8, ), 'RUNE' => array ( 'symbol' => 'RUNE', 'minorUnit' => 8, ), 'RVN' => array ( 'symbol' => 'RVN', 'minorUnit' => 8, ), 'S' => array ( 'symbol' => 'S', 'minorUnit' => 8, ), 'SAGA' => array ( 'symbol' => 'SAGA', 'minorUnit' => 8, ), 'SAND' => array ( 'symbol' => 'SAND', 'minorUnit' => 8, ), 'SANTOS' => array ( 'symbol' => 'SANTOS', 'minorUnit' => 8, ), 'SC' => array ( 'symbol' => 'SC', 'minorUnit' => 8, ), 'SCR' => array ( 'symbol' => 'SCR', 'minorUnit' => 8, ), 'SCRT' => array ( 'symbol' => 'SCRT', 'minorUnit' => 8, ), 'SEI' => array ( 'symbol' => 'SEI', 'minorUnit' => 8, ), 'SFP' => array ( 'symbol' => 'SFP', 'minorUnit' => 8, ), 'SHELL' => array ( 'symbol' => 'SHELL', 'minorUnit' => 8, ), 'SHIB' => array ( 'symbol' => 'SHIB', 'minorUnit' => 8, ), 'SIGN' => array ( 'symbol' => 'SIGN', 'minorUnit' => 8, ), 'SKL' => array ( 'symbol' => 'SKL', 'minorUnit' => 8, ), 'SLF' => array ( 'symbol' => 'SLF', 'minorUnit' => 8, ), 'SLP' => array ( 'symbol' => 'SLP', 'minorUnit' => 8, ), 'SNX' => array ( 'symbol' => 'SNX', 'minorUnit' => 8, ), 'SOL' => array ( 'symbol' => 'SOL', 'minorUnit' => 8, ), 'SOLV' => array ( 'symbol' => 'SOLV', 'minorUnit' => 8, ), 'SOPH' => array ( 'symbol' => 'SOPH', 'minorUnit' => 8, ), 'SPELL' => array ( 'symbol' => 'SPELL', 'minorUnit' => 8, ), 'SSV' => array ( 'symbol' => 'SSV', 'minorUnit' => 8, ), 'STEEM' => array ( 'symbol' => 'STEEM', 'minorUnit' => 8, ), 'STG' => array ( 'symbol' => 'STG', 'minorUnit' => 8, ), 'STO' => array ( 'symbol' => 'STO', 'minorUnit' => 8, ), 'STORJ' => array ( 'symbol' => 'STORJ', 'minorUnit' => 8, ), 'STRAX' => array ( 'symbol' => 'STRAX', 'minorUnit' => 8, ), 'STRK' => array ( 'symbol' => 'STRK', 'minorUnit' => 8, ), 'STX' => array ( 'symbol' => 'STX', 'minorUnit' => 8, ), 'SUI' => array ( 'symbol' => 'SUI', 'minorUnit' => 8, ), 'SUN' => array ( 'symbol' => 'SUN', 'minorUnit' => 8, ), 'SUPER' => array ( 'symbol' => 'SUPER', 'minorUnit' => 8, ), 'SUSHI' => array ( 'symbol' => 'SUSHI', 'minorUnit' => 8, ), 'SXP' => array ( 'symbol' => 'SXP', 'minorUnit' => 8, ), 'SXT' => array ( 'symbol' => 'SXT', 'minorUnit' => 8, ), 'SYN' => array ( 'symbol' => 'SYN', 'minorUnit' => 8, ), 'SYRUP' => array ( 'symbol' => 'SYRUP', 'minorUnit' => 8, ), 'SYS' => array ( 'symbol' => 'SYS', 'minorUnit' => 8, ), 'T' => array ( 'symbol' => 'T', 'minorUnit' => 8, ), 'TAO' => array ( 'symbol' => 'TAO', 'minorUnit' => 8, ), 'TFUEL' => array ( 'symbol' => 'TFUEL', 'minorUnit' => 8, ), 'THE' => array ( 'symbol' => 'THE', 'minorUnit' => 8, ), 'THETA' => array ( 'symbol' => 'THETA', 'minorUnit' => 8, ), 'TIA' => array ( 'symbol' => 'TIA', 'minorUnit' => 8, ), 'TKO' => array ( 'symbol' => 'TKO', 'minorUnit' => 8, ), 'TLM' => array ( 'symbol' => 'TLM', 'minorUnit' => 8, ), 'TNSR' => array ( 'symbol' => 'TNSR', 'minorUnit' => 8, ), 'TON' => array ( 'symbol' => 'TON', 'minorUnit' => 8, ), 'TRB' => array ( 'symbol' => 'TRB', 'minorUnit' => 8, ), 'TRU' => array ( 'symbol' => 'TRU', 'minorUnit' => 8, ), 'TRUMP' => array ( 'symbol' => 'TRUMP', 'minorUnit' => 8, ), 'TRX' => array ( 'symbol' => 'TRX', 'minorUnit' => 8, ), 'TST' => array ( 'symbol' => 'TST', 'minorUnit' => 8, ), 'TURBO' => array ( 'symbol' => 'TURBO', 'minorUnit' => 8, ), 'TUSD' => array ( 'symbol' => 'TUSD', 'minorUnit' => 8, ), 'TUT' => array ( 'symbol' => 'TUT', 'minorUnit' => 8, ), 'TWT' => array ( 'symbol' => 'TWT', 'minorUnit' => 8, ), 'UMA' => array ( 'symbol' => 'UMA', 'minorUnit' => 8, ), 'UNI' => array ( 'symbol' => 'UNI', 'minorUnit' => 8, ), 'USD1' => array ( 'symbol' => 'USD1', 'minorUnit' => 8, ), 'USDC' => array ( 'symbol' => 'USDC', 'minorUnit' => 8, ), 'USDP' => array ( 'symbol' => 'USDP', 'minorUnit' => 8, ), 'USDT' => array ( 'symbol' => 'USDT', 'minorUnit' => 8, ), 'USTC' => array ( 'symbol' => 'USTC', 'minorUnit' => 8, ), 'USUAL' => array ( 'symbol' => 'USUAL', 'minorUnit' => 8, ), 'UTK' => array ( 'symbol' => 'UTK', 'minorUnit' => 8, ), 'VANA' => array ( 'symbol' => 'VANA', 'minorUnit' => 8, ), 'VANRY' => array ( 'symbol' => 'VANRY', 'minorUnit' => 8, ), 'VELODROME' => array ( 'symbol' => 'VELODROME', 'minorUnit' => 8, ), 'VET' => array ( 'symbol' => 'VET', 'minorUnit' => 8, ), 'VIC' => array ( 'symbol' => 'VIC', 'minorUnit' => 8, ), 'VIRTUAL' => array ( 'symbol' => 'VIRTUAL', 'minorUnit' => 8, ), 'VOXEL' => array ( 'symbol' => 'VOXEL', 'minorUnit' => 8, ), 'VTHO' => array ( 'symbol' => 'VTHO', 'minorUnit' => 8, ), 'W' => array ( 'symbol' => 'W', 'minorUnit' => 8, ), 'WAN' => array ( 'symbol' => 'WAN', 'minorUnit' => 8, ), 'WAXP' => array ( 'symbol' => 'WAXP', 'minorUnit' => 8, ), 'WBETH' => array ( 'symbol' => 'WBETH', 'minorUnit' => 8, ), 'WBTC' => array ( 'symbol' => 'WBTC', 'minorUnit' => 8, ), 'WCT' => array ( 'symbol' => 'WCT', 'minorUnit' => 8, ), 'WIF' => array ( 'symbol' => 'WIF', 'minorUnit' => 8, ), 'WIN' => array ( 'symbol' => 'WIN', 'minorUnit' => 8, ), 'WLD' => array ( 'symbol' => 'WLD', 'minorUnit' => 8, ), 'WOO' => array ( 'symbol' => 'WOO', 'minorUnit' => 8, ), 'XAI' => array ( 'symbol' => 'XAI', 'minorUnit' => 8, ), 'XEC' => array ( 'symbol' => 'XEC', 'minorUnit' => 8, ), 'XLM' => array ( 'symbol' => 'XLM', 'minorUnit' => 8, ), 'XNO' => array ( 'symbol' => 'XNO', 'minorUnit' => 8, ), 'XRP' => array ( 'symbol' => 'XRP', 'minorUnit' => 8, ), 'XTZ' => array ( 'symbol' => 'XTZ', 'minorUnit' => 8, ), 'XUSD' => array ( 'symbol' => 'XUSD', 'minorUnit' => 8, ), 'XVG' => array ( 'symbol' => 'XVG', 'minorUnit' => 8, ), 'XVS' => array ( 'symbol' => 'XVS', 'minorUnit' => 8, ), 'YFI' => array ( 'symbol' => 'YFI', 'minorUnit' => 8, ), 'YGG' => array ( 'symbol' => 'YGG', 'minorUnit' => 8, ), 'ZEC' => array ( 'symbol' => 'ZEC', 'minorUnit' => 8, ), 'ZEN' => array ( 'symbol' => 'ZEN', 'minorUnit' => 8, ), 'ZIL' => array ( 'symbol' => 'ZIL', 'minorUnit' => 8, ), 'ZK' => array ( 'symbol' => 'ZK', 'minorUnit' => 8, ), 'ZRO' => array ( 'symbol' => 'ZRO', 'minorUnit' => 8, ), 'ZRX' => array ( 'symbol' => 'ZRX', 'minorUnit' => 8, ), );PK[$W]¹¿nÖŸŸLICENSEnu„[µü¤PK[$W]îy·f´´Ö.readthedocs.ymlnu„[µü¤PK[$W]mNÒy\\ ÊREADME.mdnu„[µü¤PK[$W]û-õ' _phpstan.neonnu„[µü¤PK[$W]ݱ——’’±src/Exception.phpnu„[µü¤PK[$W]/yÏ##„src/Number.phpnu„[µü¤PK[$W]J®Ë KƒKƒß:src/MoneyFactory.phpnu„[µü¤PK[$W]ÂÝ´ž>ž> n¾src/Money.phpnu„[µü¤PK[$W][Ãì Iýsrc/CurrencyPair.phpnu„[µü¤PK[$W]*¼ž{··!—src/Parser/BitcoinMoneyParser.phpnu„[µü¤PK[$W]5ÑbÉ5 5 Ÿsrc/Parser/IntlMoneyParser.phpnu„[µü¤PK[$W],òi;¾)"src/Parser/IntlLocalizedDecimalParser.phpnu„[µü¤PK[$W]dºÅûgg#9"src/Parser/AggregateMoneyParser.phpnu„[µü¤PK[$W]a‹ø_ _ !ó%src/Parser/DecimalMoneyParser.phpnu„[µü¤PK[$W]k[Õöö£/src/Exchange/SwapExchange.phpnu„[µü¤PK[$W]´XJD55!æ3src/Exchange/IndirectExchange.phpnu„[µü¤PK[$W]WŠðPP+lDsrc/Exchange/IndirectExchangeQueuedItem.phpnu„[µü¤PK[$W]K@„ùù"Fsrc/Exchange/ExchangerExchange.phpnu„[µü¤PK[$W]¶=z‚ØØbKsrc/Exchange/FixedExchange.phpnu„[µü¤PK[$W] Ý7Eææ+ˆOsrc/Exchange/ReversedCurrenciesExchange.phpnu„[µü¤PK[$W]‚ì&ûû!ÉTsrc/Exception/ParserException.phpnu„[µü¤PK[$W]öѳå*Vsrc/Exception/UnknownCurrencyException.phpnu„[µü¤PK[$W]_9Í͆†)uWsrc/Exception/DivisionByZeroException.phpnu„[µü¤PK[$W]öä´„„'TXsrc/Exception/ModuloByZeroException.phpnu„[µü¤PK[$W]R �œ3/Ysrc/Exception/UnresolvableCurrencyPairException.phpnu„[µü¤PK[$W]ìñÑn$¤\src/Exception/FormatterException.phpnu„[µü¤PK[$W]8Ô>œ:src/Exchange.phpnu„[µü¤PK[$W]H¨ �÷÷=src/Calculator.phpnu„[µü¤PK[$W]Å@ D§§SLsrc/TellerFactory.phpnu„[µü¤PK[$W]–••›óphpcs.xml.distnu„[µü¤PK[$W]+8ÿh=h= nûCHANGELOG.mdnu„[µü¤PK[$W]0®Å­ ­ 9composer.jsonnu„[µü¤PK[$W]òc¶ccüFresources/currency.phpnu„[µü¤PK[$W]a؈Ãoo$Fªresources/generate-money-factory.phpnu„[µü¤PK[$W]*nPå´ ´ % ²resources/generate-teller-factory.phpnu„[µü¤PK[$W]µþe!u!u¼resources/binance.phpnu„[µü¤PK::ùx1