Repository navigation
Make fulus production ready for finance - #11
Merged
Merged
Conversation
Convert applied the ratio to minor units, so EUR 1.00 at EUR/JPY 160.25 gave JPY 16,025. The ratio is now read in major units, as markets quote it, and Convert adjusts for the minor units of each currency. Signed-off-by: ayn <ayn.khatib@gmail.com>
An unset mode silently truncated. The modes now start at 1, so the zero value returns ErrInvalidRoundingMode. RoundUnnecessary returns ErrInexact when the exact result needs rounding. Signed-off-by: ayn <ayn.khatib@gmail.com>
Money[currency.Currency] compiled and then panicked with a nil dereference.
The new constraint currency.Unit requires ~struct{}, and TestTypeSafety
type-checks that invalid currency types do not compile.
Signed-off-by: ayn <ayn.khatib@gmail.com>
The generator skipped every ISO 4217 entry for a ZZ country, so XAU, XAG, XPT and XPD were missing. It now skips only XTS and XXX. When ISO 4217 has no minor units, the generator uses the CLDR digits and says so in the doc comment, instead of a silent default of 2. Signed-off-by: ayn <ayn.khatib@gmail.com>
AnyMoney.Add and Sub allocated three big.Int values for each call. They now use the same checked int64 arithmetic as Money and do not allocate. Signed-off-by: ayn <ayn.khatib@gmail.com>
Distribute returned plain int64 chunk sizes, Allocate wrapped the parts in an Allocation with a redundant Total, and Validate took int64 bounds. Distribution is now generic with Money fields, Allocate is variadic and returns []Money[T], and Validate takes Money bounds. Signed-off-by: ayn <ayn.khatib@gmail.com>
Ratio had exported fields, so a negative or zero literal converted without an error. Rate[Base, Quote] has a validating constructor and adds Invert, Cross and text encoding. Cross takes Rate[A, B] and Rate[B, C], so the compiler checks a triangulation. Convert now returns only the Money value. Signed-off-by: ayn <ayn.khatib@gmail.com>
MulDecimal parsed a string on each call, so a typo failed only at run time and in the hot path. Factor is parsed one time with ParseFactor, which also reads percentages, and Percent and Bps build common factors. ParseFactor and ParseRate reject exponents, because big.Rat can allocate a very large number for an input such as 1e999999999. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
An int64 amount limits a token with 18 minor units to about 9.2 units, which is not enough for crypto or trading. Money now holds a 128-bit two's complement integer, with 192-bit intermediate products and a math/big fallback only for terms that do not fit. Amount is replaced by Int64, BigInt and NewMoneyFromBigInt. A value is 16 bytes and stays comparable with ==. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
JSON held the amount in minor units with no scale, so a payload changed its
value if the reader had other minor units, for example after an ISO 4217
change. MarshalJSON now writes {"amount":"10.50","currency":"USD"} and
UnmarshalJSON checks the scale against the minor units.
Signed-off-by: ayn <ayn.khatib@gmail.com>
Signed-off-by: ayn <ayn.khatib@gmail.com>
Scan read integer text as minor units, so a NUMERIC value of 1050 dollars loaded as $10.50, and it failed on NUMERIC text such as 10.50. Value and Scan now use the canonical decimal for NUMERIC columns, with a scale check. BigintMoney stores minor units in an integer column, so the column type is always explicit. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
A change of the minor units in the ISO 4217 data changes the value of every amount that is stored in minor units. A golden file now records the minor units of each generated currency, a test compares the data with it, and CI fails if a stable release changes or removes a line. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
String used a global default locale, so log lines and test output changed with a process-wide setting. String now gives the currency code and the canonical decimal, for example "USD -1234.50". Format(loc) is the only localized output. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
The Currency interface required FormatInfo, so every currency, the core package and each binary that imports it pulled in the CLDR tables. Currency now needs only Code and MinorUnits, with Numbered and Named as optional interfaces. The format package holds Money, AnyMoney, Parse, ParseAny and the Formatter interface for custom data. Parse now also accepts the minus sign of the locale for a pattern without a negative subpattern. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
Custom currencies could only go into one global registry, so tenants and tests shared state. Registry is now a type with ByCode, ByNumber, Register and All, and the package functions use Default(). Register also rejects a nil currency and negative minor units. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
The property tests checked only identities such as commutativity. checkMoneyOps compares Add, Sub, Mul, Neg, Abs, Div, MulFactor, Convert and RoundCash, for every rounding mode, with a math/big reference that does not share code with the package. checkAllocate does the same for the largest remainder method. FuzzDifferential runs both with random 128-bit amounts. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
CI now fails if the coverage of the fulus and format packages is below 95%, and reports benchstat results for each pull request. A Scorecard workflow publishes the OpenSSF analysis. A release workflow checks that the tag is signed, creates the GitHub release with a source archive and adds SLSA level 3 provenance. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
gRPC services exchange money as google.type.Money. fulusproto converts Money and AnyMoney to and from it without rounding. It is a separate module, so the fulus module keeps no dependencies. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
The README, the package documentation and the design documents now show the format package, Rate, Factor, the decimal JSON and SQL forms, and the fulusproto module. The README programs compile and give the shown output. Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com> Signed-off-by: ayn <ayn.khatib@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix Convert across minor units, make rounding explicit, and tighten the currency type constraint.
Move to 128-bit amounts, opaque Rate and Factor types, decimal JSON and NUMERIC SQL, and a separate format package.
Add currency registries, differential tests, CI coverage, benchmark, Scorecard and SLSA release checks, and the fulusproto module.