Platform Address System#
Attention
Address-based state transitions were enabled in Protocol Version 11. These transitions enable direct operations using Platform addresses without requiring a pre-existing identity for some operations.
Overview#
Address-based state transitions provide an alternative funding and transfer mechanism using Platform addresses. Unlike identity-signed transactions that require an existing identity with keys, address-based operations can work directly with cryptographic proofs tied to address ownership.
There are six address-based state transition types:
Type |
Name |
Description |
|---|---|---|
9 |
Transfer credits from identity to Platform addresses |
|
10 |
Create identity funded from Platform addresses |
|
11 |
Top up existing identity from Platform addresses |
|
12 |
Transfer between Platform addresses |
|
13 |
Fund Platform addresses from asset lock |
|
14 |
Withdraw from Platform addresses to Core |
Common Components#
Platform Address#
Platform addresses are derived from standard Bitcoin/Dash address formats and encoded as bech32m strings per DIP-0018. The human-readable part (HRP) is dash on mainnet and tdash on testnet, devnet, and regtest. The 21-byte payload is type_byte || Hash160(compressed_pubkey), where Hash160 = RIPEMD160(SHA256(x)). The checksum is bech32m (BIP-350).
Variant |
Type Byte |
Description |
|---|---|---|
|
0xb0 |
Pay-to-Public-Key-Hash |
|
0x80 |
Pay-to-Script-Hash |
Note
A PlatformAddress has two distinct byte encodings depending on context. The type bytes above (0xb0 / 0x80) apply to the user-facing bech32m encoding — what appears in address strings like dash1k.... Internal GroveDB storage keys use bincode variant indices 0x00 / 0x01 instead. Decoding one through the other’s code path will fail.
Address Witness#
Witnesses provide cryptographic proof of address ownership. Each input in an address-based transition requires a corresponding witness.
Variant |
Size |
Fields |
Description |
|---|---|---|---|
|
65 bytes |
signature |
Recoverable ECDSA signature |
|
Varies |
signatures, redeemScript |
Multiple signatures with multisig redeem script |
P2PKH Verification:
Double-SHA256 hash the signable bytes
Recover public key from recoverable signature
Hash160 the recovered pubkey
Compare with address hash
P2SH Multisig Verification:
Verify redeem script hashes to address
Parse script for threshold (M) and public keys (N)
Double-SHA256 hash the signable bytes (reused for all signatures)
Match M signatures to N public keys in order
See the witness implementation in rs-dpp.
Fee Strategy#
The fee strategy specifies how transaction fees are deducted from inputs or outputs.
Step Type |
Type |
Size |
Description |
|---|---|---|---|
|
unsigned integer |
16 bits |
Deduct fee from input at specified index |
|
unsigned integer |
16 bits |
Reduce output amount to cover fee |
Note
Fee strategy cannot be empty. Maximum steps: 4 (max_address_fee_strategies). No duplicate steps allowed. Steps are processed in sequence until the fee is fully covered.
Common Type Aliases#
Type |
Definition |
Size |
Description |
|---|---|---|---|
|
unsigned integer |
32 bits |
Sequential counter per address (prevents replay) |
|
unsigned integer |
64 bits |
Platform credit unit |
|
unsigned integer |
16 bits |
User-specified fee multiplier |
Platform Address State Transition Details#
Identity Credit Transfer to Addresses#
Transfer credits from an existing identity to one or more Platform addresses.
Field |
Type |
Size |
Description |
|---|---|---|---|
identityId |
array of bytes |
32 bytes |
An Identity ID for the identity sending credits |
recipientAddresses |
map |
Varies |
Map of destination Platform addresses to credit amounts |
nonce |
unsigned integer |
64 bits |
Identity nonce for this transition to prevent replay attacks |
userFeeIncrease |
unsigned integer |
16 bits |
Extra fee to prioritize processing if the mempool is full |
signaturePublicKeyId |
unsigned integer |
32 bits |
The ID of the public key used to sign the state transition |
signature |
array of bytes |
65 bytes |
Signature of state transition data |
Note
Minimum recipients: 1. Maximum recipients: max_address_outputs. Minimum per recipient: 500,000 credits. Fee: 500,000 credits base + 6,000,000 credits per recipient (example: 1 recipient = 6,500,000 credits minimum fee).
See the implementation in rs-dpp.
Identity Create from Addresses#
Create a new identity funded from Platform address balances.
Field |
Type |
Size |
Description |
|---|---|---|---|
publicKeys |
array of keys |
Varies |
Public key(s) for the new identity (1-6 keys) |
inputs |
map |
Varies |
Map of source Platform addresses to (nonce, credits) pairs |
output |
tuple |
Varies |
(Optional) Change output as (Platform address, credits) |
feeStrategy |
array |
Varies |
|
userFeeIncrease |
unsigned integer |
16 bits |
Extra fee to prioritize processing if the mempool is full |
inputWitnesses |
array |
Varies |
Address witnesses for each input |
Note
Constraints: Minimum inputs: 1. Maximum inputs: max_address_inputs. Maximum public keys: 6. Minimum per input: 100,000 credits. Minimum output: 500,000 credits. Minimum funding: input sum ≥ output sum + 200,000 credits.
Cost: Base cost 2,000,000 + 6,500,000 per key. Example: 2 keys = 15,000,000 credits.
See the implementation in rs-dpp.
Identity Top-Up from Addresses#
Add credits to an existing identity from Platform address balances.
Field |
Type |
Size |
Description |
|---|---|---|---|
identityId |
array of bytes |
32 bytes |
An Identity ID for the identity receiving the top-up |
inputs |
map |
Varies |
Map of source Platform addresses to (nonce, credits) pairs |
output |
tuple |
Varies |
(Optional) Change output as (Platform address, credits) |
feeStrategy |
array |
Varies |
|
userFeeIncrease |
unsigned integer |
16 bits |
Extra fee to prioritize processing if the mempool is full |
inputWitnesses |
array |
Varies |
Address witnesses for each input |
Note
Constraints: Minimum inputs: 1. Maximum inputs: max_address_inputs. Minimum per input: 100,000 credits. Minimum output: 500,000 credits. Minimum top-up: input sum ≥ output sum + 200,000 credits.
Fee: Base top-up cost: 500,000 credits.
See the implementation in rs-dpp.
Address Funds Transfer#
Transfer credits between Platform addresses.
Field |
Type |
Size |
Description |
|---|---|---|---|
inputs |
map |
Varies |
Map of source Platform addresses to (nonce, credits) pairs |
outputs |
map |
Varies |
Map of destination Platform addresses to credit amounts |
feeStrategy |
array |
Varies |
|
userFeeIncrease |
unsigned integer |
16 bits |
Extra fee to prioritize processing if the mempool is full |
inputWitnesses |
array |
Varies |
Address witnesses for each input |
Important
Unlike other address transitions, fund transfers enforce strict balance preservation. The total input amount must exactly equal the total output amount (before fee deduction).
Note
Constraints: Minimum inputs: 1. Maximum inputs: max_address_inputs. Minimum outputs: 1. Maximum outputs: max_address_outputs. Minimum per input: 100,000 credits. Minimum per output: 500,000 credits. No output can also be an input.
Fee: 500,000 credits per input + 6,000,000 credits per output.
See the implementation in rs-dpp.
Address Funding from Asset Lock#
Fund Platform addresses from a Core chain asset lock special transaction.
Field |
Type |
Size |
Description |
|---|---|---|---|
assetLockProof |
object |
Varies |
Asset lock proof proving locked funds (Instant or Chain) |
inputs |
map |
Varies |
(Optional) Map of existing Platform addresses to combine |
outputs |
map |
Varies |
Map of destination addresses to credits (one must be None for remainder) |
feeStrategy |
array |
Varies |
|
userFeeIncrease |
unsigned integer |
16 bits |
Extra fee to prioritize processing if the mempool is full |
signature |
array of bytes |
65 bytes |
Asset lock signature |
inputWitnesses |
array |
Varies |
Address witnesses for any existing address inputs |
This transition uses dual signing: an asset lock signature proves ownership of locked funds, and address witnesses prove ownership of any existing address inputs (if combining funds).
Important
Exactly one output must have a None value. This remainder output receives whatever funds remain after explicit outputs and fees are satisfied, ensuring full consumption of the asset lock.
Note
Constraints: Minimum outputs: 1. Maximum inputs: max_address_inputs. Maximum outputs: max_address_outputs. Minimum per input: 100,000 credits. Minimum per explicit output: 500,000 credits. No output can also be an input.
See the implementation in rs-dpp.
Address Credit Withdrawal#
Withdraw credits from Platform addresses back to the Core chain.
Field |
Type |
Size |
Description |
|---|---|---|---|
inputs |
map |
Varies |
Map of source Platform addresses to (nonce, credits) pairs |
output |
tuple |
Varies |
(Optional) Change output as (Platform address, credits) |
feeStrategy |
array |
Varies |
|
coreFeePerByte |
unsigned integer |
32 bits |
Core transaction fee per byte (must be a Fibonacci number ≥ 1) |
pooling |
unsigned integer |
8 bits |
Pooling mode: |
outputScript |
array of bytes |
Varies |
Core chain destination script (P2PKH or P2SH only) |
userFeeIncrease |
unsigned integer |
16 bits |
Extra fee to prioritize processing if the mempool is full |
inputWitnesses |
array |
Varies |
Address witnesses for each input |
Note
Constraints: Minimum inputs: 1. Maximum inputs: max_address_inputs. Minimum per input: 100,000 credits. Minimum output: 500,000 credits. Pooling must be Never (others not yet implemented). Output script must be P2PKH or P2SH. The withdrawn amount (input sum minus the change output) must be greater than zero and within the min and max withdrawal amount limits.
Fee: 400,000,000 credits. Withdrawal fees are significantly higher due to the complexity and finality of moving funds back to the Core chain.
See the implementation in rs-dpp.
Address State Transition Signing#
Address-based state transitions use different signing methods depending on the type. See the state transition signing page for full signing details.
Category |
Transitions |
Signer |
|---|---|---|
Identity-signed |
Type 9 |
Existing identity key |
Address-witness-signed |
Types 10, 11, 12, 14 |
Address owner(s) |
Dual (Asset lock + Address) |
Type 13 |
Asset lock owner + optional address owners |
Other Sources of Address Balance Changes#
Platform address balances do not change only through the address transitions above. Shielded pool activity can also credit an address:
An Unshield net output
A Shield from Asset Lock surplus
The Identity Create From Shielded Pool fallback credit, paid to
sendToAddressOnCreationFailurewhen identity creation fails a stateful check
Since protocol version 13, these shielded-origin credits, along with the balance effects of paid-but-invalid state transitions, are recorded in the recent per-block address balance change set that incremental client sync reads. Because the recorded set feeds the committed state root, the expansion was not in effect before protocol version 13.
The recent per-block set is served by the getRecentAddressBalanceChanges and getRecentCompactedAddressBalanceChanges endpoints.