SettleMint
Developer guidesAPI integration

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

  • decimals is an integer from 0 through 18.
  • 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.50 with 2 decimals becomes 1050.
  • 1.5 tokens with 18 decimals becomes 1500000000000000000.
  • 100 shares with 0 decimals stays 100.

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:

  • totalSupply is a decimal value serialized for API clients.
  • totalSupplyExact, when present, is the raw on-chain integer.
  • Monetary fields such as basePrice are 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

MistakeProblemFix
Sending "1.5" as a mutation amountMutation endpoints expect the scaled smallest-unit amountConvert with human_amount × 10^decimals first
Using number, float, or double for large quantitiesThe runtime can round values silentlyUse BigInt, BigInteger, or a decimal library
Sending scientific notation such as "1.5e18"It is not a stable audit format for exact-value reviewSend the full integer string
Assuming every asset has 18 decimalsShares and some regulated instruments may use 0 or 2 decimalsRead the asset's decimals field before calculating
Matching one amount to multiple recipientsBatch mutations require aligned recipient and amount arraysSend 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>"
    }
  }'

On this page