How the Osmosis Agent Toolkit Handles Token Denominations with Different Decimals
The Osmosis Agent Toolkit normalizes token amounts by querying decimal metadata from the Chain Registry, then applies precision-aware arithmetic to convert between human-readable values and on-chain minimal denominations.
The jonator/osmosis-agent-toolkit provides TypeScript utilities that enable AI agents to interact with the Osmosis decentralized exchange. When agents transact with assets ranging from 6-decimal OSMO to 18-decimal bridged Ethereum tokens, the toolkit ensures accurate conversion between floating-point user inputs and the integer values required by Cosmos SDK chain APIs.
Decimal Discovery via Chain Registry
The toolkit determines the correct decimal exponent for any token by querying the Chain Registry asset definitions. This metadata resides in the denom_units array within each asset object, where the exponent for the display denomination indicates the number of decimal places.
In packages/core/src/tools/account.ts (lines 55‑63), the toolkit locates the asset and extracts the exponent:
const asset = this.osmosisAssets.find(a => a.base === denom);
const decimals = asset?.denom_units
.find(u => u.denom === asset.display)
?.exponent ?? 6;
The same pattern appears in packages/core/src/tools/swap.ts (lines 72‑76 and 166‑170), ensuring that both balance queries and swap operations use consistent decimal logic. The exponent field specifies the power of 10 by which the minimal denomination differs from the human-readable unit.
Scaling Up: Converting Human-Readable Amounts
Before sending values to the side-car API, the toolkit scales floating-point amounts up to their minimal denomination (micro-units) by multiplying by 10^n, where n equals the token’s decimal count. To prevent floating-point precision loss, this operation uses the mulPrecision helper implemented in packages/core/src/utils/number.ts (lines 7‑38).
The function signature is:
export function mulPrecision(num: number, precision: number): bigint { … }
This string-based arithmetic operation safely converts numbers like 2.5 into integer bigints like 2500000 for a 6-decimal token, avoiding JavaScript’s inherent floating-point inaccuracies.
Scaling Down: Parsing On-Chain Responses
When the side-car API returns amounts in minimal denominations, the toolkit converts these back to human-readable formats for display or quoting purposes. This simple division operation appears in both swap quote tools.
In packages/core/src/tools/swap.ts, the SwapQuoteInGivenOutTool (lines 90‑94) and SwapQuoteOutGivenInTool (lines 184‑188) perform the conversion:
const amountWithDecimals = parseInt(quote.amount_in) / 10 ** decimals;
This calculation transforms micro-denomination strings (e.g., "1250000") into display-ready values (e.g., 1.25) that agents can present to users.
Fallback Strategy for Missing Metadata
If the Chain Registry lacks denom_units for a specific asset, the toolkit implements a default fallback of 6 decimals. This default aligns with the common convention for Osmosis-native assets like OSMO and ATOM, ensuring that unknown tokens still process correctly rather than failing outright.
Summary
- Chain Registry integration: The toolkit queries asset metadata to discover each token’s decimal exponent via the
denom_unitsarray. - Safe scaling: The
mulPrecisionfunction inpackages/core/src/utils/number.tsconverts human inputs to minimal denominations using string-based arithmetic to avoid floating-point errors. - Bidirectional conversion: Scaling down divides API responses by
10^decimalsto produce readable amounts. - Robust defaults: Missing metadata triggers a fallback to 6 decimals, maintaining compatibility with standard Cosmos assets.
Frequently Asked Questions
How does the toolkit determine the number of decimals for a specific token?
The toolkit searches the Chain Registry asset list for the target denomination, then locates the denom_units entry matching the asset’s display property. The exponent field of that unit provides the decimal count, as implemented in packages/core/src/tools/account.ts and packages/core/src/tools/swap.ts.
What prevents floating-point errors when converting amounts?
The mulPrecision function in packages/core/src/utils/number.ts uses string-based arithmetic rather than native JavaScript multiplication to scale numbers by 10^n. This approach eliminates floating-point precision loss when converting human-readable values to the bigint integers required by chain APIs.
How does the toolkit handle tokens not listed in the Chain Registry?
When an asset’s denom_units array is undefined or missing the display denomination entry, the toolkit defaults to 6 decimals. This fallback ensures compatibility with standard Osmosis assets and prevents transaction failures due to metadata gaps.
Which tools utilize the decimal conversion logic?
The decimal handling logic spans multiple tools: AccountTool uses it for balance formatting, while SwapQuoteInGivenOutTool and SwapQuoteOutGivenInTool apply it for quote calculations. All share the same mulPrecision utility and Chain Registry lookup patterns defined in the core package.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →