Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
459 changes: 0 additions & 459 deletions docs/cardano/IssuerDID.md

This file was deleted.

25 changes: 0 additions & 25 deletions docs/cardano/index.md

This file was deleted.

38 changes: 38 additions & 0 deletions docs/prism/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
id: configuration
title: Configuration
---

The `did:prism` resolver can be configured to use a custom endpoint for resolving short-form DIDs. This is useful if you want to use your own resolver or a resolver provided by a third party.

## Agent Configuration

The easiest way to configure the `did:prism` resolver is to provide the `resolverEndpoint` option when initializing the `Agent`.

Here's an example of how to configure the `Agent` to use a custom resolver endpoint:

```typescript
import { Agent } from '@hyperledger/identus-sdk';

const agent = Agent.initialize({
pluto: myPlutoInstance,
options: {
resolverEndpoint: 'https://my-custom-resolver.com/dids/',
},
});
```

The `resolverEndpoint` should be the base URL of the resolver, and the DID will be appended to it. For example, if you are resolving `did:prism:123`, the resolver will make a GET request to `https://my-custom-resolver.com/dids/did:prism:123`.

The default resolver endpoint is `https://raw.githubusercontent.com/FabioPinheiro/prism-vdr/refs/heads/main/mainnet/diddoc/`.

## Castor Configuration

If you are using `Castor` directly, you can configure the resolver endpoint in the `Castor` constructor:

```typescript
import { Apollo, Castor } from '@hyperledger/identus-sdk';

const apollo = new Apollo();
const castor = new Castor(apollo, [], 'https://my-custom-resolver.com/dids/');
```
54 changes: 54 additions & 0 deletions docs/prism/endpoints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
id: endpoints
title: Community DID:PRISM Resolver Endpoints
---

This page provides a list of community-maintained resolver endpoints for `did:prism`. These endpoints can be used to resolve `did:prism` DIDs without needing to run your own infrastructure.

## Public Resolver Endpoints

Here is a list of public endpoints that you can use:

| Endpoint URL | Maintained By | Notes |
| :--- | :--- | :--- |
| `https://Your endpoint` | Community | Mainnet resolver. |

To resolve a DID, you can make a `GET` request to the resolver's `/1.0/identifiers/{did}` path.

**Example using cURL:**

```bash
curl 'https://Your endpoint/1.0/identifiers/did:prism:00592a141a4c2bcb7a6aa691750511e2e9b048231820125e15ab70b12a210aae' | jq
```

## Running Your Own Resolver

If you prefer to run your own resolver, you can use the community-provided Docker image. This gives you a private instance that you control.

The source code for the resolver driver can be found on [GitHub](https://github.com/FabioPinheiro/uni-resolver-driver-did-prism).

### Using Docker

The resolver is available as a Docker image.

**1. Pull the Docker image:**

```bash
docker pull ghcr.io/fabiopinheiro/uni-resolver-driver-did-prism:1.1
```

**2. Run the Docker container:**
The container listens on port `9090` by default. You can map it to any port on your host machine.

```bash
docker run -it --rm -p 9090:9090 ghcr.io/fabiopinheiro/uni-resolver-driver-did-prism:1.1
```

**3. Test your local resolver:**
Once the container is running, you can test it by trying to resolve a DID:

```bash
curl 'http://localhost:9090/1.0/identifiers/did:prism:00592a141a4c2bcb7a6aa691750511e2e9b048231820125e15ab70b12a210aae' | jq
```

If you wish to contribute by adding your public resolver to this list, please submit a pull request to update this page.
218 changes: 218 additions & 0 deletions docs/prism/publishing-did.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
---
id: publishing-did
title: Publishing a did:prism on Cardano (End-to-End Guide)
---

Publishing a `did:prism` DID on the Cardano blockchain allows you to create a short-form DID that can be easily shared and resolved by others. This guide provides an end-to-end example of how to achieve this in a browser-based environment using React and the Mesh SDK.

## Prerequisites

* A CIP30-compliant wallet extension installed in your browser (e.g., Eternl, Nami, or Flint).
* Some ADA in your wallet to pay for transaction fees.
* A [Blockfrost](https://blockfrost.io/dashboard) API key for a project on the Cardano Mainnet.

## Required Packages

First, you need to install the following packages in your project:

```bash
npm install @hyperledger/identus-sdk @meshsdk/core @meshsdk/react
```

## Environment Setup

Create a `.env.local` file in your project's root directory and add your Blockfrost API key:

```
NEXT_PUBLIC_BLOCKFROST_API_KEY=your_blockfrost_api_key
```

## End-to-End Example with React and Mesh

The following example demonstrates the complete process of creating and publishing a `did:prism` DID on Cardano using a React component and the Mesh SDK. This approach simplifies wallet interaction and transaction building.

To use this component, you must wrap your application with the `MeshProvider` from `@meshsdk/react`.

**Example `pages/_app.tsx`:**
```typescript
import type { AppProps } from "next/app";
import { MeshProvider } from "@meshsdk/react";

function MyApp({ Component, pageProps }: AppProps) {
return (
<MeshProvider>
<Component {...pageProps} />
</MeshProvider>
);
}

export default MyApp;
```

**Example Publishing Component:**
```typescript
import React, { useState, useCallback } from "react";
import SDK from "@hyperledger/identus-sdk";
import { useWallet, CardWallet } from "@meshsdk/react";
import { Transaction } from "@meshsdk/core";

// Helper to split data into chunks for Cardano metadata
function splitStringIntoChunks(input: Uint8Array, chunkSize = 64): Uint8Array[] {
const buffer = Buffer.from(input);
const chunks: Uint8Array[] = [];
for (let i = 0; i < buffer.length; i += chunkSize) {
chunks.push(
Uint8Array.from(buffer.slice(i, i + chunkSize))
);
}
return chunks;
}

// Helper to check for transaction confirmation on Blockfrost
async function checkTransactionConfirmation(txHash: string) {
// NOTE: This requires a Blockfrost API key to be configured in your environment
const projectId = process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY;
if (!projectId) {
throw new Error("Blockfrost API key is not configured.");
}
try {
const response = await fetch(
`https://cardano-mainnet.blockfrost.io/api/v0/txs/${txHash}`,
{
headers: { project_id: projectId },
}
);
return response.ok;
} catch (error) {
console.error("Error checking transaction confirmation:", error);
return false;
}
}

export function PublishDidComponent() {
const { wallet, connected } = useWallet();
const [did, setDid] = useState<SDK.Domain.DID | null>(null);
const [txHash, setTxHash] = useState<string | null>(null);
const [isPublishing, setIsPublishing] = useState(false);
const [isConfirmed, setIsConfirmed] = useState(false);
const [error, setError] = useState<string | null>(null);

const publishDid = useCallback(async () => {
if (!connected || !wallet) {
setError("Please connect a wallet first.");
return;
}

setIsPublishing(true);
setError(null);
setTxHash(null);
setIsConfirmed(false);

try {
// 1. Initialize Apollo and Castor
const apollo = new SDK.Apollo();
const castor = new SDK.Castor(apollo);

// 2. Create a master key and a DID
const masterPrivateKey = apollo.createPrivateKey({
type: SDK.Domain.KeyTypes.EC,
curve: SDK.Domain.Curve.SECP256K1,
seed: Buffer.from(apollo.createRandomSeed().seed.value).toString("hex"),
});

const services: SDK.Domain.Service[] = []; // Add any services if needed
const newDid = await castor.createPrismDID(masterPrivateKey, services);
setDid(newDid);

// 3. Prepare the metadata for the transaction
const atalaObject = await castor.createPrismDIDAtalaObject(masterPrivateKey, newDid);
const metadataBody = {
v: 1,
c: splitStringIntoChunks(atalaObject),
};

// 4. Build, sign, and submit the transaction with Mesh
const tx = new Transaction({ initiator: wallet })
.setMetadata(21325, metadataBody);

const unsignedTx = await tx.build();
const signedTx = await wallet.signTx(unsignedTx);
const submittedTxHash = await wallet.submitTx(signedTx);
setTxHash(submittedTxHash);

// 5. Wait for confirmation
console.log(`Transaction submitted. Hash: ${submittedTxHash}. Waiting for confirmation...`);
let confirmed = false;
while (!confirmed) {
await new Promise(resolve => setTimeout(resolve, 15000)); // Wait 15s
confirmed = await checkTransactionConfirmation(submittedTxHash);
}

setIsConfirmed(true);
console.log("Transaction confirmed! DID published successfully.");

} catch (err) {
console.error(err);
setError(err instanceof Error ? err.message : "An unknown error occurred.");
} finally {
setIsPublishing(false);
}
}, [wallet, connected]);

return (
<div>
<h2>Publish a did:prism DID</h2>
{!connected ? (
<CardWallet />
) : (
<button onClick={publishDid} disabled={isPublishing}>
{isPublishing ? "Publishing..." : "Create and Publish DID"}
</button>
)}

{error && <p style={{ color: "red" }}>Error: {error}</p>}

{did && <p>DID created: {did.toString()}</p>}

{txHash && (
<div>
<p>Transaction Hash: {txHash}</p>
<p>
<a href={`https://cardanoscan.io/transaction/${txHash}`} target="_blank" rel="noopener noreferrer">
View on Cardanoscan
</a>
</p>
</div>
)}

{isPublishing && !isConfirmed && <p>Waiting for transaction confirmation...</p>}
{isConfirmed && <p style={{ color: "green" }}>DID Published Successfully!</p>}
</div>
);
}
```

### Explanation of the Code

This example provides a self-contained React component, `PublishDidComponent`, that handles the entire lifecycle of creating and publishing a `did:prism`.

1. **Component Setup and Helpers:**
* The component uses React state to manage the DID, transaction status, and any potential errors.
* It uses the `useWallet` hook from `@meshsdk/react` to get the connected wallet's state and instance.
* `splitStringIntoChunks` is a helper function to correctly format the DID operation data for Cardano's transaction metadata.
* `checkTransactionConfirmation` is a helper to poll the Blockfrost API and verify when the transaction is confirmed on the blockchain.

2. **`publishDid` Function:** This is the core logic, triggered by a button click.
* **Initialization:** It initializes the `Apollo` and `Castor` modules from the Atala PRISM SDK.
* **DID Creation:** It creates a new master private key and uses it to generate a new, unpublished `did:prism`.
* **Metadata Preparation:** It calls `createPrismDIDAtalaObject` to generate the specific data structure required for the publication operation. This data is then chunked for the metadata.
* **Transaction with Mesh:** It uses Mesh's `Transaction` builder, which provides a simple and elegant API. It sets the metadata for the transaction using the standard label for PRISM DID operations (`21325`).
* **Signing and Submission:** The transaction is built, signed by the user through their connected wallet, and submitted to the blockchain.
* **Confirmation:** The component then polls for confirmation and updates the UI to reflect the successful publication.

3. **User Interface:**
* It renders Mesh's `CardWallet` component to allow users to easily connect their CIP30 wallet.
* Once connected, it displays a button to initiate the publishing process.
* It provides real-time feedback to the user, showing the created DID, transaction hash, and final confirmation status.

After the transaction is confirmed, your `did:prism` is published on the Cardano blockchain, and its short-form DID can be resolved by anyone.
45 changes: 45 additions & 0 deletions docs/prism/resolving-did.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
id: resolving-did
title: Resolving a did:prism
---

A `did:prism` DID can be resolved to a DID Document, which contains information about the DID, such as its public keys and services.

## Resolving with the Agent

If you have an `Agent` instance, you can use its `castor` instance to resolve a `did:prism` DID.

Here's an example of how to resolve a `did:prism` DID using the `Agent`:

```typescript
import { Agent } from '@hyperledger/identus-sdk';

const agent = Agent.initialize({
pluto: myPlutoInstance,
});

const did = 'did:prism:b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k';
const didDocument = await agent.castor.resolveDID(did);

console.log(didDocument);
```

The `resolveDID` method will automatically handle both long-form and short-form DIDs. For short-form DIDs, it will use the configured `resolverEndpoint` to fetch the DID Document.

## Resolving with Castor

If you are using `Castor` directly, you can use the `resolveDID` method to resolve a `did:prism` DID.

Here's an example of how to resolve a `did:prism` DID using `Castor`:

```typescript
import { Apollo, Castor } from '@hyperledger/identus-sdk';

const apollo = new Apollo();
const castor = new Castor(apollo);

const did = 'did:prism:b6c0c33d701ac1b9a262a14454d1bbde3d127d697a76950963c5fd930605:Cj8KPRI7CgdtYXN0ZXIwEAFKLgoJc2VmsxEiECSTjyV7sUfCr_ArpN9rvCwR9fRMAhcsr_S7ZRiJk4p5k';
const didDocument = await castor.resolveDID(did);

console.log(didDocument);
```
Loading
Loading