Register a Data Contract
Overview
In this tutorial we will register a data contract.
For this tutorial you will need:
- A wallet mnemonic with some funds in it: Tutorial: Create and Fund a Wallet
- A dash platform identity: Tutorial: Register an Identity
Code
Defining contract documents
As described in the data contract explanation, data contracts must include one or more developer-defined documents.
The most basic example below (tab 1) demonstrates a data contract containing a single document type (note
) which has a single string property (message
).
The second tab shows the same data contract with an index defined on the $ownerId
field. This would allow querying for documents owned by a specific identity using a where clause.
The third tab shows a data contract using the JSON-Schema $ref feature that enables reuse of defined objects.
{
"note": {
"properties": {
"message": {
"type": "string"
}
},
"additionalProperties": false
}
}
{
"note": {
"indices": [
{
"properties": [{ "$ownerId": "asc" }], "unique": false },
],
"properties": {
"message": {
"type": "string"
}
},
"additionalProperties": false
}
}
/*
An identity's documents are accessible via a query including a where clause like:
{
where: [['$ownerId', '==', 'an identity id']],
}
*/
{
customer: {
properties: {
name: { type: "string" },
billing_address: { $ref: "#/definitions/address" },
shipping_address: { $ref: "#/definitions/address" }
},
additionalProperties: false
},
}
/*
The contract document defined above is dependent on the following object
being added to the contract via the contracts `.setDefinitions` method:
{
address: {
type: "object",
properties: {
street_address: { type: "string" },
city: { type: "string" },
state: { type: "string" }
},
required: ["street_address", "city", "state"],
additionalProperties: false
}
}
*/
Please refer to the data contract reference page for more comprehensive details related to contracts and documents.
Registering the data contract
The following examples demonstrate the details of creating contracts using the features described above:
const Dash = require('dash');
const clientOpts = {
network: 'evonet',
wallet: {
mnemonic: 'a Dash wallet mnemonic with evonet funds goes here',
}
};
const client = new Dash.Client(clientOpts);
const registerContract = async function () {
try {
const platform = client.platform;
const identity = await platform.identities.get('an identity ID goes here');
const contractDocuments = {
note: {
properties: {
message: {
type: "string"
}
},
additionalProperties: false
}};
const contract = await platform.contracts.create(contractDocuments, identity);
console.dir({contract});
// Make sure contract passes validation checks
const validationResult = await platform.dpp.dataContract.validate(contract);
if (validationResult.isValid()) {
console.log("validation passed, broadcasting contract..");
// Sign and submit the data contract
await platform.contracts.broadcast(contract, identity);
} else {
console.error(validationResult) // An array of detailed validation errors
throw validationResult.errors[0];
}
} catch (e) {
console.error('Something went wrong:', e);
} finally {
client.disconnect();
}
}
registerContract();
const Dash = require('dash');
const clientOpts = {
network: 'evonet',
wallet: {
mnemonic: 'a Dash wallet mnemonic with evonet funds goes here',
}
};
const client = new Dash.Client(clientOpts);
const registerContract = async function () {
try {
const platform = client.platform;
const identity = await platform.identities.get('an identity ID goes here');
const contractDocuments = {
note: {
indices: [
{
properties: [{ "$ownerId": "asc" }], unique: false },
],
properties: {
message: {
type: "string"
}
},
additionalProperties: false
}};
const contract = await platform.contracts.create(contractDocuments, identity);
console.dir({contract});
// Make sure contract passes validation checks
const validationResult = await platform.dpp.dataContract.validate(contract);
if (validationResult.isValid()) {
console.log("validation passed, broadcasting contract..");
// Sign and submit the data contract
await platform.contracts.broadcast(contract, identity);
} else {
console.error(validationResult) // An array of detailed validation errors
throw validationResult.errors[0];
}
} catch (e) {
console.error('Something went wrong:', e);
} finally {
client.disconnect();
}
}
registerContract();
const Dash = require('dash');
const clientOpts = {
network: 'evonet',
wallet: {
mnemonic: 'a Dash wallet mnemonic with evonet funds goes here',
}
};
const client = new Dash.Client(clientOpts);
const registerContract = async function () {
try {
const platform = client.platform;
const identity = await platform.identities.get('an identity ID goes here');
// Define a reusable object
const definitions = {
address: {
type: "object",
properties: {
street_address: { type: "string" },
city: { type: "string" },
state: { type: "string" }
},
required: ["street_address", "city", "state"],
additionalProperties: false
}
}
// Create a document with properties using a definition via $ref
const contractDocuments = {
customer: {
properties: {
name: { type: "string" },
billing_address: { $ref: "#/definitions/address" },
shipping_address: { $ref: "#/definitions/address" }
},
additionalProperties: false
},
};
const contract = await platform.contracts.create(contractDocuments, identity);
// Add reusable definitions referred to by "$ref" to contract
contract.setDefinitions(definitions)
console.dir({contract});
// Make sure contract passes validation checks
const validationResult = await platform.dpp.dataContract.validate(contract);
if (validationResult.isValid()) {
console.log("validation passed, broadcasting contract..");
// Sign and submit the data contract
await platform.contracts.broadcast(contract, identity);
} else {
console.error(validationResult) // An array of detailed validation errors
throw validationResult.errors[0];
}
} catch (e) {
console.error('Something went wrong:', e);
} finally {
client.disconnect();
}
}
registerContract();
What's Happening
After we initialize the Client, we create an object defining the documents this data contract requires (e.g. a note
document in the example). The platform.contracts.create
method takes two arguments: a contract definitions JSON-schema object and an identity. The contract definitions object consists of the document types being created (e.g. note
). It defines the properties and any indices.
Once the data contract has been created, we still need to submit it to DAPI. The platform.contracts.broadcast
method takes a data contract and an identity parameter. Internally, it creates a State Transition containing the previously created contract, signs the state transition, and submits the signed state transition to DAPI. A response will only be returned if an error is encountered,
Updated about 4 years ago