Contract Tokens#
Contract Token Overview#
The tokens object defines each type of token in the data contract. At a minimum, a token must define conventions. All other fields have sensible defaults. Each token must be assigned a unique position within the contract and follow the token constraints.
Note
The protocol only requires conventions. However, some SDKs (e.g., the JavaScript SDK) may require change control rules to be provided explicitly.
The following example shows a minimal tokens object defining a single token with basic conventions:
{
"tokens": {
"0": {
"$format_version": "0",
"conventions": {
"$format_version": "0",
"localizations": {
"en": {
"$format_version": "0",
"shouldCapitalize": false,
"singularForm": "credit-token",
"pluralForm": "credit-tokens"
}
},
"decimals": 8
}
}
}
}
Tokens may also define distribution rules, history tracking, marketplace rules, and various configuration options. Refer to this table for a brief description of the major token sections:
Feature |
Description |
|---|---|
Display properties including localization, decimals, and naming conventions |
|
Behavioral settings for token operations, freezing, and emergency actions |
|
Authorization rules governing who can modify token parameters |
|
Rules for token distribution, minting destinations, and pricing |
|
Configuration for recording token operations in Platform history |
Token Creation Fees#
Token creation incurs specific fees based on which token features are used:
Operation |
Fee (DASH) |
Description |
|---|---|---|
Token registration |
Base fee for adding a token to a contract |
|
Perpetual distribution |
Fee for enabling perpetual distribution |
|
Pre-programmed distribution |
Fee for enabling pre-programmed distribution |
|
Search keyword fee |
Per keyword fee for including search keywords |
Assigning Position#
Each token in the tokens object must be assigned a unique position value, with ordering starting at zero and incrementing with each token. The position is used as the key in the tokens object and indicates which token to perform operations on when a contract contains multiple tokens.
{
"tokens": {
"0": { /* first token definition */ },
"1": { /* second token definition */ },
"2": { /* third token definition */ }
}
}
Token Conventions#
The conventions object defines the display and formatting properties of a token. It includes localization settings, decimal precision, and naming conventions that determine how the token is presented to users.
Localization#
The localizations object contains language-specific display properties using ISO 639-1 language codes as keys. Each localization entry includes:
Property |
Type |
Description |
|---|---|---|
|
string |
Version of the localization format (currently “0”) |
|
boolean |
Whether the token name should be capitalized when displayed |
|
string |
Singular form of the token name |
|
string |
Plural form of the token name |
"localizations": {
"en": {
"$format_version": "0",
"shouldCapitalize": true,
"singularForm": "loyalty-point",
"pluralForm": "loyalty-points"
},
"es": {
"$format_version": "0",
"shouldCapitalize": false,
"singularForm": "punto-de-lealtad",
"pluralForm": "puntos-de-lealtad"
}
}
Note
An English (en) localization entry is required. Tokens without an en key in the localizations map will fail protocol validation with a MissingDefaultLocalizationError.
Decimal Precision#
The decimals property specifies the number of decimal places for token amounts. This affects how token balances are displayed and calculated. If decimals is set to zero, token operations (e.g., mint, transfer) will only allow integer amounts.
"conventions": {
"$format_version": "0",
"localizations": { /* ... */ },
"decimals": 8 // 8 decimal places (default)
}
Token Configuration#
Token configuration controls behavioral aspects of token operations, including supply management, operational controls, and security features.
General#
Property |
Type |
Description |
|---|---|---|
|
string |
Optional text describing the token’s purpose or behavior (3–100 characters) |
Supply Management#
Property |
Type |
Description |
|---|---|---|
|
unsigned integer |
Initial supply of tokens created at contract deployment |
|
unsigned integer |
Maximum number of tokens that can ever exist (null for unlimited) |
Operational Controls#
Property |
Type |
Description |
|---|---|---|
|
boolean |
Whether the token begins in a paused state where tokens cannot be transferred |
|
boolean |
Whether transfers to frozen balances are permitted |
Control Group Management#
Property |
Type |
Description |
|---|---|---|
|
unsigned integer |
Position assigned to the main control group |
|
string |
Authorization level for modifying the main control group |
Example:
{
"baseSupply": 1000000,
"maxSupply": 10000000,
"startAsPaused": false,
"allowTransferToFrozenBalance": true,
"mainControlGroup": null,
"mainControlGroupCanBeModified": "NoOne"
}
Token Change Control Rules#
Change control rules define authorization requirements for modifying various aspects of a token after deployment. These rules specify who can make changes and under what conditions.
Change Rule Structure#
Each rule consists of the following parameters defined in DPP that control its behavior:
Field |
Description |
|---|---|
|
This is who is authorized to make such a change. Valid values are listed in the authorized parties table. |
|
This is who is authorized to make such a change to the people authorized to make a change. Valid values are listed in the authorized parties table. |
|
Are we allowed to change to |
|
Are we allowed to change the admin action takers to |
|
Can the admin action takers change themselves (default: false) |
Example
"<rule_name>": {
"V0": {
"authorized_to_make_change": "ContractOwner",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
}
Available Change Rules#
Tokens support the following change control rules:
Rule Name |
Description |
|---|---|
|
Controls who can modify token conventions (localization) |
|
Controls who can modify the maximum supply limit |
|
Controls who can modify perpetual distribution settings (subset of |
|
Controls who can change where new tokens are sent (subset of |
|
Controls who can modify minting destination rules (subset of |
|
Controls who can set direct purchase pricing (subset of |
|
Controls who can modify trade mode rules (subset of |
|
Controls who can manually mint tokens |
|
Controls who can manually burn tokens |
|
Controls who can freeze token balances |
|
Controls who can unfreeze token balances |
|
Controls who can destroy frozen funds |
|
Controls who can execute emergency actions |
Example:
"manualMintingRules": {
"V0": {
"authorized_to_make_change": "ContractOwner",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
}
Token Distribution Rules#
Distribution rules govern how tokens are created, allocated, and priced within the platform. These rules provide flexible mechanisms for token distribution and marketplace integration.
Distribution Properties#
Property |
Type |
Description |
|---|---|---|
|
object |
Ongoing distribution mechanism for continuous token allocation |
|
object |
Change control rules for perpetual distribution |
|
string |
Default identity to receive newly minted tokens |
|
object |
Change control rules for destination identity |
|
boolean |
Whether minting operations can specify custom destinations |
|
object |
Change control rules for destination choice |
|
object |
Scheduled token allocations at predetermined timestamps |
|
object |
Change control rules for direct purchase pricing |
Perpetual Distribution#
Perpetual distribution enables ongoing token allocation. The following configuration distributes 100 tokens to the contract owner every 60 minutes (3600000 ms):
"perpetualDistribution": {
"$format_version": "0",
"distributionType": {
"TimeBasedDistribution": {
"interval": 3600000,
"function": {
"FixedAmount": {
"amount": 100
}
}
}
},
"distributionRecipient": "ContractOwner"
}
Distribution Types#
The distributionType field accepts one of three schedule types:
Type |
Interval Unit |
Description |
|---|---|---|
|
Block height |
Emits tokens every N blocks. If |
|
Milliseconds |
Emits tokens every N milliseconds. If |
|
Epochs |
Emits tokens every N epochs. If |
Each type wraps an interval (the period length) and a function (the emission pattern from the options below).
Perpetual Distribution Options#
A wide variety of emission patterns are provided to cover most common scenarios. The following table summarizes the options and links to further details.
Name |
Description |
|---|---|
Emits a constant number of tokens per period |
|
Emits a random amount between |
|
Emits tokens that decrease in discrete steps at fixed intervals |
|
Linear growth/decay with integer or fractional precision |
|
Polynomial with integer or fractional exponents or coefficients |
|
Emits tokens following an exponential function |
|
Slows emission over time |
|
Slows emission over time |
|
Emits constant values within predefined steps |
Fixed Amount#
Emits a constant (fixed) number of tokens for every period.
Formula:
f(x) = nUse Case:
When a predictable, unchanging reward is desired.
Simplicity and stable emissions.
Example: If
n = 5tokens per block, then after 3 blocks the total emission is 15 tokens.
Random#
Emits a random number of tokens within a specified range.
Formula:
f(x) ∈ [min, max]Constraints:
minmust be ≤max, otherwise the function is invalid.If
min == max, this behaves like a Fixed Amount function with a constant emission.
Description
This function selects a random token emission amount between
minandmax.The value is drawn uniformly between the bounds.
The randomness uses a Pseudo Random Function (PRF) from x.
Use Case
Stochastic Rewards: Introduces randomness into rewards to incentivize unpredictability.
Lottery-Based Systems: Used for randomized emissions, such as block rewards with probabilistic payouts.
Example
Suppose a system emits between 10 and 100 tokens per period.
Random { min: 10, max: 100 }Period (x)
Emitted Tokens (Random)
1
27
2
94
3
63
4
12
Each period, the function emits a random number of tokens between
min = 10andmax = 100.Over time, the average reward trends toward the midpoint
(min + max) / 2.
Step Decreasing Amount#
Emits tokens that decrease in discrete steps at fixed intervals.
Formula:
f(x) = distribution_start_amount * (1 - (decrease_per_interval_numerator / decrease_per_interval_denominator))^((x - start_decreasing_offset) / step_count)Description: Reduces token emissions by a fixed percentage at regular intervals.
step_count(u32): number of periods between each stepdecrease_per_interval_numerator(u16): reduction factor numeratordecrease_per_interval_denominator(u16): reduction factor denominatorstart_decreasing_offset(optional u64): start period offset. If not provided, the contract creation start is used. Before this offset,distribution_start_amountis emitted every interval.distribution_start_amount(TokenAmount): initial token emission amountmax_interval_count(optional u16): maximum number of decreasing intervals. Defaults to 128 if not set. After this many cycles,trailing_distribution_interval_amountis emitted per interval. Maximum value: 1024.trailing_distribution_interval_amount(TokenAmount): token emission after all decreasing intervals are exhaustedmin_value(optional u64): minimum emission floor
Use Case: Reward systems with predictable decay—ideal for Bitcoin-style halvings or Dash-style gradual reductions
Example:
Bitcoin: 50% reduction every 210,000 blocks
Dash: ~7% reduction every 210,240 blocks
Linear#
Emits tokens following a linear function that can increase or decrease over time with fractional precision.
Formula:
f(x) = (a * (x - s) / d) + bDescription: Supports both integer and fractional slopes via
a / dratio. Enables precise reward schedules without floating-point rounding errors.Parameters
a: slope numerator (positive = increase, negative = decrease)d: slope divisor (enables fractional precision)s(start_step): optional start period offset (defaults to contract creation)b(starting_amount): starting emission amountmin_value/max_value: optional emission bounds
Behavior
If
a > 0, emissions increase linearly over timeIf
a < 0, emissions decrease linearly over timeIf
a = 0, emissions remain constant atb
Use Case: Predictable inflation or deflation, gradual reward scaling, clamped emission schedules
Example:
Increasing Linear Emission:
f(x) = (1 * (x - 0) / 1) + 10Decreasing Linear Emission:
f(x) = (-2 * (x - 0) / 1) + 100Delayed Start:
f(x) = (5 * (x - 10) / 1) + 50Clamping Emissions:
f(x) = (2 * (x - 0) / 1) + 50
Polynomial#
A polynomial function using fixed-point arithmetic for fractional or integer exponents.
Formula:
f(x) = (a * (x - s + o)^(m / n)) / d + bDescription:
Emits tokens based on a polynomial curve, where the exponent is defined as a fraction (m / n). This enables a wide range of growth or decay behaviors—linear, quadratic, root-based, and more—using precise fixed-point logic.
Parameters:a: coefficient scaling the curve (positive for growth, negative for decay)mandn: exponent numerator and denominator, allowing fractional powers (e.g.,m = 1,n = 2→ square root)d: divisor to scale the results(start_moment): optional start period offseto: offset inside the exponent inputb: amount added after the curve is computedmin_value/max_value: optional boundaries to clamp emissions
Use Case:
Accelerating Growth: Use
a > 0andm > 1for quadratic/cubic growthDiminishing Emissions: Use
a < 0and fractional exponents for decaying curvesRoot-based Models: Use
m = 1,n > 1to slow down early growthFlexibility: Fine-tune emission behavior with high control over shape
Example:
Increasing Polynomial Growth:
f(x) = (2 * (x - s + o)^2) / d + 10Decreasing Polynomial Decay:
f(x) = (5 * (x - s + o)^(-1)) / d + 10Inverted Growth → Decreasing Over Time:
f(x) = (-3 * (x - s + o)^2) / d + 50Inverted Decay → Slowing Increase:
f(x) = (-10 * (x - s + o)^(-2)) / d + 50
Exponential#
Emits tokens following an exponential function.
Formula:
f(x) = (a * e^(m * (x - s + o) / n)) / d + bDescription: Exponential growth or decay depending on parameter signs
Use Case: Early contributor boosts or quick emission tapering
Logarithmic#
Logarithmic growth of token emissions.
Formula:
f(x) = (a * ln(m * (x - s + o) / n)) / d + bDescription: Growth slows as
xincreases (uses natural log)Use Case: Sustainable long-term emission tapering
Inverted Logarithmic#
Emits tokens following an inverted logarithmic decay curve.
Formula:
f(x) = (a * log(n / (m * (x - s + o)))) / d + bDescription:
Emits a high number of tokens initially, with emissions decreasing rapidly at first, then slowing over time. Useful when early adoption or front-loaded incentives are desired.
Parameters:a: scaling factor for the log termd: divisor to scale the final resultmandn: Control the logarithmic inversiono: offset applied inside the logarithms(start_moment): optional start period offset (defaults to contract creation time if not provided)b: offset added after scalingmin_value/max_value: optional bounds to constrain emissions
Use Case:
Gradual Decay of Rewards: Prioritize early users with higher emissions that reduce over time
Resource Draining / Controlled Burn: Designed for token models where supply tapers gradually
Airdrops & Grants: Rewards diminish for late claimants, encouraging early participation
Example:
f(x) = (1000 * log(5000 / (5 * (x - 1000)))) / 10 + 10Sample outputs:
Period (x)
Emission (f(x))
1000
500 tokens
1500
230 tokens
2000
150 tokens
5000
50 tokens
10,000
20 tokens
50,000
10 tokens
Starts high and decays gradually without hitting zero too fast
Stepwise#
Emits tokens in fixed amounts for specific intervals.
Description: Emissions remain constant within each step
Use Case: Adjust rewards at specific milestones
Example: 100 tokens per block for first 1000 blocks, then 50 tokens thereafter
Pre-Programmed Distribution#
Pre-programmed distribution allows scheduling specific token allocations at predetermined times. The following configuration distributes 3 sets of tokens to the same identity at the defined timestamps:
"preProgrammedDistribution": {
"$format_version": "0",
"distributions": {
"1749662152621": {
"2yZbE3TAZAhLwNVQk7JMUUuBXgrVt1NG172PGjeUfjUo": 100
},
"1749665692621": {
"2yZbE3TAZAhLwNVQk7JMUUuBXgrVt1NG172PGjeUfjUo": 1000
},
"1781198092621": {
"2yZbE3TAZAhLwNVQk7JMUUuBXgrVt1NG172PGjeUfjUo": 1000000
}
}
}
Direct Purchase Pricing#
Direct purchase pricing enables tokens to be purchased directly using Platform:
"changeDirectPurchasePricingRules": {
"V0": {
"authorized_to_make_change": "ContractOwner",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
}
Token History Tracking#
Token history tracking controls which operations are recorded in Platform’s historical records. This provides audit trails and transparency for token operations.
History Properties#
Property |
Type |
Default |
Description |
|---|---|---|---|
|
boolean |
true |
Record all token transfers |
|
boolean |
true |
Record freeze/unfreeze operations |
|
boolean |
true |
Record token minting events |
|
boolean |
true |
Record token burning events |
|
boolean |
true |
Record direct purchase price changes |
|
boolean |
true |
Record direct purchase transactions |
Example:
"keepsHistory": {
"$format_version": "0",
"keepsTransferHistory": true,
"keepsFreezingHistory": true,
"keepsMintingHistory": true,
"keepsBurningHistory": true,
"keepsDirectPricingHistory": true,
"keepsDirectPurchaseHistory": false
}
Token Marketplace Rules#
Marketplace rules define how tokens can be traded within Platform’s built-in marketplace system.
Trade Modes#
Mode |
Description |
|---|---|
|
Token cannot be traded on the marketplace |
Example:
"marketplaceRules": {
"$format_version": "0",
"tradeMode": "NotTradeable",
"tradeModeChangeRules": {
"V0": {
"authorized_to_make_change": "NoOne",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
}
}
Token Distribution Function Parameters#
The distribution functions use the following parameters defined across various implementations:
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
integer |
- |
Coefficient/scaling factor |
|
integer |
- |
Base offset or constant term |
|
integer |
- |
Additional offset |
|
integer |
1 |
Divisor for precision control |
|
integer |
- |
Exponent numerator |
|
integer |
1 |
Exponent denominator |
|
integer |
0 |
Offset inside function input |
|
integer |
0 |
Start period offset |
|
integer |
- |
Minimum emission bound |
|
integer |
- |
Maximum emission bound |
|
integer |
- |
Periods between steps |
|
integer |
- |
Reduction factor numerator |
|
integer |
- |
Reduction factor denominator |
|
integer |
- |
Time interval in milliseconds |
Note
Parameter sign types vary by function: a is unsigned (u64) for Exponential but signed (i64) for all other functions. m is unsigned (u64) for Logarithmic and InvertedLogarithmic but signed (i64) for Polynomial and Exponential.
Distribution Recipients#
Recipient |
Description |
|---|---|
|
Tokens sent to the contract owner |
|
Tokens sent to a specific identity |
|
Tokens distributed to evonodes proportional to their participation (only valid with |
See also
For all protocol constants, see Protocol Constants.
Token Constraints#
For performance and security reasons, tokens have the following constraints:
General Constraints#
Parameter |
Value |
|---|---|
Maximum number of keywords |
|
Keyword length |
|
Description length |
|
Maximum note length |
|
Maximum number of tokens per contract |
Only limited by maximum contract size |
Convention Constraints#
Parameter |
Value |
|---|---|
Language code length |
|
Token name length (singular) |
|
Token name length (plural) |
|
Decimal places |
|
Maximum localization entries |
Only limited by maximum contract size |
Supply Constraints#
Parameter |
Value |
|---|---|
Maximum token amount |
Example Syntax#
This example shows the complete structure of a token definition with all major configuration options:
{
"tokens": {
"0": {
"$format_version": "0",
"conventions": {
"$format_version": "0",
"localizations": {
"en": {
"$format_version": "0",
"shouldCapitalize": true,
"singularForm": "reward-token",
"pluralForm": "reward-tokens"
}
},
"decimals": 8
},
"conventionsChangeRules": {
"V0": {
"authorized_to_make_change": "NoOne",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"baseSupply": 1000000,
"maxSupply": 10000000,
"keepsHistory": {
"$format_version": "0",
"keepsTransferHistory": true,
"keepsFreezingHistory": true,
"keepsMintingHistory": true,
"keepsBurningHistory": true,
"keepsDirectPricingHistory": true,
"keepsDirectPurchaseHistory": true
},
"startAsPaused": false,
"allowTransferToFrozenBalance": true,
"maxSupplyChangeRules": {
"V0": {
"authorized_to_make_change": "ContractOwner",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"distributionRules": {
"$format_version": "0",
"perpetualDistribution": null,
"perpetualDistributionRules": {
"V0": {
"authorized_to_make_change": "NoOne",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"preProgrammedDistribution": null,
"newTokensDestinationIdentity": null,
"newTokensDestinationIdentityRules": {
"V0": {
"authorized_to_make_change": "ContractOwner",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"mintingAllowChoosingDestination": true,
"mintingAllowChoosingDestinationRules": {
"V0": {
"authorized_to_make_change": "ContractOwner",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"changeDirectPurchasePricingRules": {
"V0": {
"authorized_to_make_change": "ContractOwner",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
}
},
"marketplaceRules": {
"$format_version": "0",
"tradeMode": "NotTradeable",
"tradeModeChangeRules": {
"V0": {
"authorized_to_make_change": "NoOne",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
}
},
"manualMintingRules": {
"V0": {
"authorized_to_make_change": "ContractOwner",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"manualBurningRules": {
"V0": {
"authorized_to_make_change": "ContractOwner",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"freezeRules": {
"V0": {
"authorized_to_make_change": "NoOne",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"unfreezeRules": {
"V0": {
"authorized_to_make_change": "NoOne",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"destroyFrozenFundsRules": {
"V0": {
"authorized_to_make_change": "NoOne",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"emergencyActionRules": {
"V0": {
"authorized_to_make_change": "NoOne",
"admin_action_takers": "NoOne",
"changing_authorized_action_takers_to_no_one_allowed": false,
"changing_admin_action_takers_to_no_one_allowed": false,
"self_changing_admin_action_takers_allowed": false
}
},
"mainControlGroup": null,
"mainControlGroupCanBeModified": "NoOne",
"description": "Reward token for customer loyalty program"
}
}
}