Description
Stellar assets can have different decimal precisions (XLM uses 7 decimal places; custom tokens may use 2, 6, or 18). When computing each recipient's share from a raw token amount, integer arithmetic on differing scales produces silently wrong results — either overpaying or underpaying recipients. The contract must normalize amounts to a canonical scale before any split calculation and denormalize before token transfer.
Technical Context
contracts/split/src/lib.rs — #[contractimpl] pay() and release_funds() entry points; contracts/split/src/types.rs — Invoice and RecipientShare structs (add token_decimals: u32 field); contracts/split/src/math.rs (new helper module) — normalize_amount(raw: i128, decimals: u32) -> i128 and denormalize_amount(normalized: i128, decimals: u32) -> i128 functions; soroban_sdk::token::Client::decimals() called against the payment token during initialize() to populate the stored decimal count.
Acceptance Criteria
Description
Stellar assets can have different decimal precisions (XLM uses 7 decimal places; custom tokens may use 2, 6, or 18). When computing each recipient's share from a raw token amount, integer arithmetic on differing scales produces silently wrong results — either overpaying or underpaying recipients. The contract must normalize amounts to a canonical scale before any split calculation and denormalize before token transfer.
Technical Context
contracts/split/src/lib.rs—#[contractimpl]pay()andrelease_funds()entry points;contracts/split/src/types.rs—InvoiceandRecipientSharestructs (addtoken_decimals: u32field);contracts/split/src/math.rs(new helper module) —normalize_amount(raw: i128, decimals: u32) -> i128anddenormalize_amount(normalized: i128, decimals: u32) -> i128functions;soroban_sdk::token::Client::decimals()called against the payment token duringinitialize()to populate the stored decimal count.Acceptance Criteria
Invoicestores the payment token's decimal count, populated fromsoroban_sdk::token::Client::decimals()duringinitialize()normalize_amountscales all raw amounts to a fixed 7-decimal internal representation before split arithmeticdenormalize_amountconverts back to the token's native scale before eachtoken::Client::transfer()callcontracts/split/src/tests/decimal_tests.rsverifies correct per-recipient amounts for tokens with 2, 6, and 7 decimal places across at least three split configurationschecked_mul,checked_div) is used throughout and propagatesError::ArithmeticOverflowon out-of-range inputs