Asset decimals
Send and read DALP asset amounts without losing precision.
DALP asset amounts are integers scaled by the asset's decimal precision. Send the smallest unit value to mutation endpoints, keep decimal math out of floats, and use the asset's decimals field whenever you convert between a user-facing amount and an API amount.
Quick summary
decimalsis an integer from0through18.- Mutation amounts use scaled integers, usually sent as strings in JSON.
- Mint amounts must be positive and the recipient count must match the amount count.
- Read responses may expose display values and raw exact values separately. Use the raw exact value when you need the on-chain integer.
- Formula:
scaled_value = human_amount × 10^decimals.
Why scaled integers?
Financial systems cannot rely on binary floating-point arithmetic for token amounts. A value such as 0.1 + 0.2 can produce 0.30000000000000004, which is unsafe for regulated asset operations.
DALP uses integer values for token quantities, the same way payment systems store cents instead of dollars:
$10.50with 2 decimals becomes1050.1.5tokens with 18 decimals becomes1500000000000000000.100shares with 0 decimals stays100.
The asset's decimals field defines the scale. DALP validates decimal precision as a whole number between 0 and 18.
Request amounts
When you call mutation endpoints such as minting, send the raw scaled integer. For JSON callers, use a string so JavaScript, JSON parsers, proxies, and client libraries do not round large values.
Single amount:
{
"amounts": "1500000000000000000"
}Multiple amounts:
{
"recipients": ["0x1111111111111111111111111111111111111111", "0x2222222222222222222222222222222222222222"],
"amounts": ["1500000000000000000", "500000000000000000"]
}Typed DALP clients may validate asset amount values as bigint, numbers, or dnum tuples. For public HTTP integrations, prefer integer strings in JSON. Integer strings are precise, easy to log, and match the values sent to smart contracts.
Do not send decimal fractions as mutation amounts
"amounts": "1.5" is not the same thing as 1.5 tokens. Convert the amount to the asset's smallest unit before sending
it.
Convert a user amount before sending it
To send 1.5 tokens for an asset with 18 decimals:
1. Split the amount: whole = "1", fraction = "5"
2. Right-pad the fraction to 18 digits: "500000000000000000"
3. Concatenate: "1" + "500000000000000000"
4. Send: "1500000000000000000"For 0-decimal assets, the user amount must already be a whole number. 100 shares is "100"; 100.5 shares is not valid for an asset with 0 decimals.
Use arbitrary-precision integer arithmetic for conversion. In JavaScript, keep the input as text and convert with BigInt after you have removed the decimal point:
function toScaledAmount(input: string, decimals: number): string {
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 18) {
throw new Error("Decimals must be an integer from 0 through 18");
}
const parts = input.split(".");
if (parts.length > 2) {
throw new Error("Amount must use at most one decimal separator");
}
const [whole, fraction = ""] = parts;
if (!/^\d+$/.test(whole ?? "") || !/^\d*$/.test(fraction)) {
throw new Error("Amount must be a non-negative decimal string");
}
if (fraction.length > decimals) {
throw new Error("Amount has more fractional digits than the asset supports");
}
return `${whole}${fraction.padEnd(decimals, "0")}`.replace(/^0+(?=\d)/, "");
}
toScaledAmount("1.5", 18); // "1500000000000000000"
toScaledAmount("10.50", 2); // "1050"
toScaledAmount("100", 0); // "100"Read amounts from the API
Asset read responses include the asset's decimals value. They can also include amount fields at different levels of precision:
totalSupplyis a decimal value serialized for API clients.totalSupplyExact, when present, is the raw on-chain integer.- Monetary fields such as
basePriceare decimal values and should be parsed as arbitrary-precision decimals, not floats.
Example asset response:
{
"name": "ACME Holdings Common Stock",
"symbol": "ACME",
"decimals": 0,
"totalSupply": "1000000",
"totalSupplyExact": "1000000",
"basePrice": "100.50"
}If your integration reconciles balances against contract state, persist the raw exact value where the API provides one. For operator screens, format the display amount with the asset's decimal precision and the user's locale.
Dnum values in SDK and typed integrations
DALP uses dnum tuples in typed code to carry both the integer value and its precision:
[1500000000000000000n, 18];The first element is the raw scaled bigint. The second element is the decimal precision. DALP serializers emit dnum values as locale-independent decimal strings, such as "1.500000000000000000". DALP serializers can also read the older serialized tuple form when needed for compatibility.
Do not hand-write JSON dnum tuples for mutation requests unless the specific client layer you use documents that wire format. Plain scaled integer strings are the safe default for HTTP calls.
Check asset decimals before minting or transferring
Retrieve the asset before preparing a mutation amount:
curl -X GET "https://your-platform.example.com/api/token/0x9459D52E60edBD3178f00F9055f6C117a21b4220" \
-H "X-Api-Key: <api-key>"Use the returned decimals value to scale the amount you send. If your workflow queues a mint or transfer, store both the operator-facing amount and the raw scaled value in your own audit trail so later reviewers can reproduce the calculation.
Common mistakes
| Mistake | Problem | Fix |
|---|---|---|
Sending "1.5" as a mutation amount | Mutation endpoints expect the scaled smallest-unit amount | Convert with human_amount × 10^decimals first |
Using number, float, or double for large quantities | The runtime can round values silently | Use BigInt, BigInteger, or a decimal library |
Sending scientific notation such as "1.5e18" | It is not a stable audit format for exact-value review | Send the full integer string |
| Assuming every asset has 18 decimals | Shares and some regulated instruments may use 0 or 2 decimals | Read the asset's decimals field before calculating |
| Matching one amount to multiple recipients | Batch mutations require aligned recipient and amount arrays | Send one amount per recipient |
Full example
This example mints 1.5 units of an 18-decimal asset to one eligible recipient.
# Step 1: Read the asset and confirm decimals.
curl -X GET "https://your-platform.example.com/api/token/0x1234567890abcdef1234567890abcdef12345678" \
-H "X-Api-Key: <api-key>"
# Step 2: Convert 1.5 to the scaled integer.
# 1.5 × 10^18 = 1500000000000000000
# Step 3: Send the scaled integer string in the mint request.
curl -X POST "https://your-platform.example.com/api/token/0x1234567890abcdef1234567890abcdef12345678/mint" \
-H "X-Api-Key: <api-key>" \
-H "Content-Type: application/json" \
-d '{
"recipients": ["0x1111111111111111111111111111111111111111"],
"amounts": ["1500000000000000000"],
"walletVerification": {
"verificationType": "PINCODE",
"secretVerificationCode": "<verification-code>"
}
}'Related guides
- Mint assets explains the full issuance flow around a mint request.
- Forced transfer covers administrative transfers.
- API reference lists the available API endpoints.