```{eval-rst} .. _explanations-dashpay: ``` # DashPay ## Overview DashPay is one of the first applications of Dash Platform's [data contracts](../explanations/platform-protocol-data-contract.md) . At its core DashPay is a data contract that enables a decentralized application that creates bidirectional [direct settlement payment channels](../reference/glossary.md#direct-settlement-payment-channel-dspc) between [identities](../explanations/identity.md). The DashPay contract enables an improved Dash wallet experience with features including: * **User Centric Interaction**: DashPay brings users front and center in a cryptocurrency wallet. Instead of sending to an address, a user sends directly to another user. Users will have a username, a display name, an avatar and a quick bio/information message. * **Easy Payments**: Once two users have exchanged contact requests, each can make payments to the other without manually sharing addresses via emails, texts or BIP21 QR codes. This is because every contact request contains the information (an encrypted extended public key) required to send payments to the originator of the request. When decrypted, this extended public key can be used by the recipient of the contact request to generate payment addresses for the originator of the contact request. * **Payment History**: When a contact is established, a user can easily track the payments they have sent to another user and the payments that they have received from that other user. A user will have an extended private key to track payments that are received from the other user and an extended public key to track payments that are sent to that other user. * **Payment Participant Protection**: The extended public keys in contact requests are encrypted in such a way that only the two users involved in a contact's two way relationship can decrypt those keys. This ensures that when any two users make payments in DashPay, only they know the sender and receiver while 3rd parties do not. ## Details The contract defines three document types: `contactRequest`, `profile` and `contactInfo`. * ContactRequest documents are the most important. They are used to establish relationships and payment channels between Dash identities. * Profile documents are used to store public facing information about Dash identities including avatars and display names. A profile can also publish optional public payment addresses (a Core chain address, a Platform address, and/or a shielded receiving address). Unlike contact-based payments, payments to the Core and Platform addresses are publicly linkable to the profile. Publishing a shielded address ties it to the profile, but shielded payments still hide the recipient on-chain. Platform checks its schema type and length; wallets must validate the shielded address before paying. * ContactInfo documents can be used to store private information about other Dash identities. ### Establishing a Contact 1. Bob installs wallet software that supports DashPay. 2. Bob [registers an identity](../tutorials/identities-and-names/register-an-identity.md) and then [creates a username](../tutorials/identities-and-names/register-a-name-for-an-identity.md) through [DPNS](../explanations/dpns.md). 3. Bob searches for Carol by her username. Behind the scenes this search returns the unique identifier for Carol's identity. An example of doing this can be seen in the [Retrieve a Name tutorial](../tutorials/identities-and-names/retrieve-a-name.md). 4. Bob sends a contact request containing an encrypted extended public key to Carol. This establishes a one way relationship from Bob to Carol. 5. Carol accepts the request by sending a contact request containing an encrypted extended public key back to Bob. This establishes a one way relationship from Carol to Bob. 6. Bob and Carol are now contacts of one another and can make payments to each other by decrypting the extended public key received from the other party and deriving payment addresses from it. Since both have established one way relationships with each other, they now have a two way relationship. If Bob gets a new device, he can use his recovery phrase from step one and restore his wallet, contacts (including Carol) and payments to and from his contacts. ```{eval-rst} .. figure:: ./img/dashpay.png :class: no-scaled-link :align: center :height: 350 :alt: Contact-based Wallet Contact-based Wallet ``` ### Implementation DashPay has many constraints as defined in the [DashPay data contract](https://github.com/dashpay/platform/blob/master/packages/dashpay-contract/schema/v2/dashpay.schema.json). Additionally, the DashPay data triggers defined in [rs-drive-abci](https://github.com/dashpay/platform/tree/master/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/batch/data_triggers/triggers/dashpay) enforce additional validation rules related to the `contactRequest` document and the Core and Platform payment address fields of the `profile` document. Note: as a system data contract, the version active on a network is determined by that network's active protocol version. :::{tip} See the [DashPay Dash Improvement Proposal (DIP)](https://github.com/dashpay/dips/blob/master/dip-0015.md) for more extensive background information and complete details about the data contract. ::: * Contact request details * Profile details * Contact Info details :::{dropdown} DashPay data contract ```json { "profile": { "type": "object", "indices": [ { "name": "ownerId", "properties": [ { "$ownerId": "asc" } ], "unique": true }, { "name": "ownerIdAndUpdatedAt", "properties": [ { "$ownerId": "asc" }, { "$updatedAt": "asc" } ] } ], "properties": { "avatarUrl": { "type": "string", "format": "uri", "minLength": 1, "maxLength": 2048, "position": 0 }, "avatarHash": { "type": "array", "byteArray": true, "minItems": 32, "maxItems": 32, "description": "SHA256 hash of the bytes of the image specified by avatarUrl", "position": 1 }, "avatarFingerprint": { "type": "array", "byteArray": true, "minItems": 8, "maxItems": 8, "description": "dHash the image specified by avatarUrl", "position": 2 }, "publicMessage": { "type": "string", "minLength": 1, "maxLength": 140, "position": 3 }, "displayName": { "type": "string", "minLength": 1, "maxLength": 25, "position": 4 }, "corePaymentAddress": { "type": "array", "byteArray": true, "minItems": 21, "maxItems": 21, "description": "Core chain address in storage form (type byte 0x00 P2PKH / 0x01 P2SH followed by the 20-byte HASH160, i.e. RIPEMD160 of SHA256, of the public key or redeem script) for public payments. The type byte is consensus-enforced by a data trigger; clients render the address as Base58Check for the network they are on. Payments to it are publicly linkable to this profile.", "position": 5 }, "platformPaymentAddress": { "type": "array", "byteArray": true, "minItems": 21, "maxItems": 21, "description": "Platform address in storage form (type byte 0x00 P2PKH / 0x01 P2SH followed by the 20-byte HASH160, i.e. RIPEMD160 of SHA256, of the public key or redeem script) for public payments. The type byte is consensus-enforced by a data trigger.", "position": 6 }, "shieldedAddress": { "type": "array", "byteArray": true, "minItems": 43, "maxItems": 43, "description": "Raw Orchard receiving address: 11-byte diversifier followed by 32-byte diversified transmission key. Clients validate before payment; wallets should use a dedicated tip account.", "position": 7 } }, "minProperties": 1, "dependentRequired": { "avatarUrl": ["avatarHash", "avatarFingerprint"], "avatarHash": ["avatarUrl", "avatarFingerprint"], "avatarFingerprint": ["avatarUrl", "avatarHash"] }, "required": [ "$createdAt", "$updatedAt" ], "additionalProperties": false }, "contactInfo": { "type": "object", "indices": [ { "name": "ownerIdAndKeys", "properties": [ { "$ownerId": "asc" }, { "rootEncryptionKeyIndex": "asc" }, { "derivationEncryptionKeyIndex": "asc" } ], "unique": true }, { "name": "ownerIdAndUpdatedAt", "properties": [ { "$ownerId": "asc" }, { "$updatedAt": "asc" } ] } ], "properties": { "encToUserId": { "type": "array", "byteArray": true, "minItems": 32, "maxItems": 32, "position": 0 }, "rootEncryptionKeyIndex": { "type": "integer", "minimum": 0, "position": 1 }, "derivationEncryptionKeyIndex": { "type": "integer", "minimum": 0, "position": 2 }, "privateData": { "type": "array", "byteArray": true, "minItems": 48, "maxItems": 2048, "position": 3, "description": "This is the encrypted values of aliasName + note + displayHidden encoded as an array in cbor" } }, "required": [ "$createdAt", "$updatedAt", "encToUserId", "privateData", "rootEncryptionKeyIndex", "derivationEncryptionKeyIndex" ], "additionalProperties": false }, "contactRequest": { "documentsMutable": false, "canBeDeleted": false, "requiresIdentityEncryptionBoundedKey": 2, "requiresIdentityDecryptionBoundedKey": 2, "type": "object", "indices": [ { "name": "ownerIdUserIdAndAccountRef", "properties": [ { "$ownerId": "asc" }, { "toUserId": "asc" }, { "accountReference": "asc" } ], "unique": true }, { "name": "ownerIdUserId", "properties": [ { "$ownerId": "asc" }, { "toUserId": "asc" } ] }, { "name": "userIdCreatedAt", "properties": [ { "toUserId": "asc" }, { "$createdAt": "asc" } ] }, { "name": "ownerIdCreatedAt", "properties": [ { "$ownerId": "asc" }, { "$createdAt": "asc" } ] } ], "properties": { "toUserId": { "type": "array", "byteArray": true, "minItems": 32, "maxItems": 32, "position": 0, "contentMediaType": "application/x.dash.dpp.identifier" }, "encryptedPublicKey": { "type": "array", "byteArray": true, "minItems": 96, "maxItems": 96, "position": 1 }, "senderKeyIndex": { "type": "integer", "minimum": 0, "position": 2 }, "recipientKeyIndex": { "type": "integer", "minimum": 0, "position": 3 }, "accountReference": { "type": "integer", "minimum": 0, "position": 4 }, "encryptedAccountLabel": { "type": "array", "byteArray": true, "minItems": 48, "maxItems": 80, "position": 5 }, "autoAcceptProof": { "type": "array", "byteArray": true, "minItems": 38, "maxItems": 102, "position": 6 } }, "required": [ "$createdAt", "$createdAtCoreBlockHeight", "toUserId", "encryptedPublicKey", "senderKeyIndex", "recipientKeyIndex", "accountReference" ], "additionalProperties": false } } ```