Skip to content

Commit

Permalink
Add HelloWorld example with Solidity contract and TypeScript integration
Browse files Browse the repository at this point in the history
Signed-off-by: dwertent <[email protected]>
  • Loading branch information
dwertent committed Jan 15, 2025
1 parent bf09215 commit b26d701
Show file tree
Hide file tree
Showing 50 changed files with 3,004 additions and 25 deletions.
2 changes: 1 addition & 1 deletion doc-site/docs/tutorials/bond-issuance.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This shows how to leverage the [Noto](../../architecture/noto/) and [Pente](../.

## Running the example

Follow the [Getting Started](../../getting-started/installation/) instructions to set up a Paldin environment, and
Follow the [Getting Started](../../getting-started/installation/) instructions to set up a Paladin environment, and
then follow the example [README](https://github.com/LF-Decentralized-Trust-labs/paladin/blob/main/example/bond/README.md)
to run the code.

Expand Down
137 changes: 137 additions & 0 deletions doc-site/docs/tutorials/hello-world.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Hello World with Paladin

This tutorial walks you through deploying and interacting with a simple `HelloWorld` smart contract using the Paladin SDK. The example demonstrates how to:
1. Deploy the contract,
2. Interact with it by calling its `sayHello` function,
3. Retrieve and verify the emitted event.

---

## Running the Example

The example code can be found in the [Paladin example repository](https://github.com/LF-Decentralized-Trust-labs/paladin/blob/main/example/public-storage).

The storage solidity contract can be found [here](https://github.com/LF-Decentralized-Trust-labs/paladin/blob/main/solidity/contracts/tutorial/Storage.sol).

Follow the [Getting Started](../../getting-started/installation/) instructions to set up a Paladin environment. Then, follow the example [README](https://github.com/LF-Decentralized-Trust-labs/paladin/blob/main/example/helloworld/README.md) to run the code.

---

### Overview

We have a `HelloWorld` smart contract, which:
- Emits a "welcome" message as an event when its `sayHello` function is called.

### Key Artifacts
To deploy and interact with the contract, we use:
1. **ABI**: Describes the contract's interface, including its functions and events.
2. **Bytecode**: The compiled contract code.

These are pre-compiled and provided in the `helloWorldJson` object.

---

### Step 1: Deploy the Contract

```typescript
const deploymentTxID = await paladin.sendTransaction({
type: TransactionType.PUBLIC, // Deploy publicly
abi: helloWorldJson.abi, // ABI of the HelloWorld contract
bytecode: helloWorldJson.bytecode, // Compiled bytecode
function: "", // No constructor arguments
from: owner.lookup, // Account signing the transaction
data: {}, // No additional data
});
```

- **What happens**:
- The `sendTransaction` method sends a deployment transaction to the Paladin network.
- The function returns a `deploymentTxID` that uniquely identifies the transaction.

### Step 2: Confirm the Deployment

```typescript
const deploymentReceipt = await paladin.pollForReceipt(deploymentTxID, 10000, true);
if (!deploymentReceipt?.contractAddress) {
logger.error("Deployment failed!");
return false;
}
logger.log("Contract deployed successfully at address:", deploymentReceipt.contractAddress);
```

- **What happens**:
- We use `pollForReceipt` to wait for the deployment transaction to be confirmed.
- If successful, the receipt includes the new `contractAddress`.

---

### Step 3: Call the `sayHello` Function

```typescript
const name = "Blocky McChainface"; // Example name for the greeting

const sayHelloTxID = await paladin.sendTransaction({
type: TransactionType.PUBLIC,
abi: helloWorldJson.abi,
function: "sayHello",
from: owner.lookup,
to: deploymentReceipt.contractAddress,
data: { name: name },
});
```

- **What happens**:
- The `sendTransaction` method sends a transaction to call the `sayHello` function of the deployed contract.
- The `data` object includes the function arguments—in this case, the `name` of the person being greeted.

---

### Step 4: Confirm the Function Call

```typescript
const functionReceipt = await paladin.pollForReceipt(sayHelloTxID, 10000, true);
if (!functionReceipt?.transactionHash) {
logger.error("Receipt retrieval failed!");
return false;
}
logger.log("sayHello function executed successfully!");
```

- **What happens**:
- Similar to the deployment step, we wait for confirmation of the `sayHello` function call using `pollForReceipt`.

---

### Step 5: Retrieve the Emitted Event

```typescript
const events = await paladin.decodeTransactionEvents(
functionReceipt.transactionHash,
helloWorldJson.abi,
"pretty=true",
);

logger.log(events[0].data["message"]);
```

- **What happens**:
- We use `decodeTransactionEvents` to extract event data from the `sayHello` transaction.

---

## Conclusion

Congratulations! You've successfully:
1. Deployed the `HelloWorld` contract,
2. Called its `sayHello` function,
3. Retrieved and validated the emitted event.

This simple example demonstrates how to interact with smart contracts using the Paladin SDK.

---

## Next Steps

Now that you’ve deployed and interacted with the `HelloWorld` contract, you’re ready to explore more complex interactions with smart contracts. In the next tutorial, we will introduce you to a **Storage** contract where you will write and read from from the blockchain!

[Continue to the Storage Contract Tutorial →](./public-storage.md)
52 changes: 37 additions & 15 deletions doc-site/docs/tutorials/index.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
## Pre-requisites
## Prerequisites

* git
* [NodeJS 20.x or newer](https://nodejs.org/en/download/package-manager) installed
- **Git**
- **Node.js 20.x or newer**
Follow the [official Node.js documentation](https://nodejs.org/en/download/package-manager) for your platform to install the appropriate version.

Clone the Paladin repository to access the examples:
To access the tutorial code, clone the Paladin repository:

```shell
git clone https://github.com/LF-Decentralized-Trust-labs/paladin.git
```

## Next Steps

The tutorials on this page provide an introduction to building on the Paladin platform. If you haven’t already, visit the [Getting Started guide](../getting-started/installation.md) to familiarize yourself with running Paladin before proceeding with any of the tutorials below.

The tutorials on this page provide a starting point for running code on top of Paladin.
<div class="grid cards" markdown>

If you haven't already, you should visit [Getting Started](../getting-started/installation/) to
ensure you're familiar with running Paladin before walking through any of the tutorials.
- :fontawesome-solid-rocket:{ .lg .middle } **[Hello World](hello-world.md)**

---

Begin with a simple “Hello World” example to get familiar with some of the basics.

- :fontawesome-solid-rocket:{ .lg .middle } **[Public Storage](public-storage.md)**

---

Explore fundamental SDK functionality for deploying and interacting with a publicly visible contract.

- :fontawesome-solid-rocket:{ .lg .middle } **[Private Storage](private-storage.md)**

---

Discover how to use **Privacy Groups** and keep contract data confidential among authorized members.

- :fontawesome-solid-rocket:{ .lg .middle } **[Notarized Tokens](notarized-tokens.md)**

---

Learn how to issue, mint, and transfer tokens using Paladin’s **Notarized Tokens** domain.

<div class="grid cards" markdown>

- :fontawesome-solid-stamp:{ .lg .middle } __[Bond Issuance](bond-issuance.md)__
- :fontawesome-solid-stamp:{ .lg .middle } **[Wholesale CBDC](zkp-cbdc.md)**

---
---

Learn how Noto and Pente work together to represent a bond issuance process.
Implement a wholesale CBDC with **zero-knowledge proof** features for enhanced privacy and regulatory compliance.

- :fontawesome-solid-stamp:{ .lg .middle } __[Wholesale CBDC](zkp-cbdc.md)__
- :fontawesome-solid-stamp:{ .lg .middle } **[Bond Issuance](bond-issuance.md)**

---
---

Learn how to implement a wholesale CBDC with Zeto.
Understand how **Notarized Tokens** and **Privacy Groups** work together to model and manage a bond issuance process.

</div>
</div>
135 changes: 135 additions & 0 deletions doc-site/docs/tutorials/notarized-tokens.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Notarized Tokens

In this tutorial, you’ll learn how to create and manage a basic token using the **Notarized Tokens (noto)** domain. Unlike the private storage example, these tokens can be transferred between nodes publicly, demonstrating how assets (e.g., “cash”) can be issued and tracked on the blockchain using Paladin.

## Prerequisites

Make sure you have:

1. Completed the [Private Storage Tutorial](./private-storage.md).
2. A **running Paladin network** with at least three nodes (Node1, Node2, Node3).

---

## Overview

This tutorial will guide you through:

1. **Deploying a Noto Token**: Use the `NotoFactory` to create a “cash token” with a specific notary.
2. **Minting Tokens**: Issue tokens to a particular node’s account.
3. **Transferring Tokens**: Send tokens between different nodes to simulate basic payments.

You can find the complete example code in the [Paladin example repository](https://github.com/LF-Decentralized-Trust-labs/paladin/tree/main/example/notarized-tokens).

---

## Step 1: Deploy a Noto Token

First, create a **Noto Factory** instance and deploy a new token. In this scenario, Node1 will act as both the notary (the entity allowed to mint tokens) and the initial recipient of the minted cash.

```typescript
logger.log("Step 1: Deploying a Noto cash token...");
const notoFactory = new NotoFactory(paladinClientNode1, "noto");
const cashToken = await notoFactory.newNoto(verifierNode1, {
notary: verifierNode1, // The notary for this token
restrictMinting: true, // Restrict minting to the notary only
});
if (!cashToken) {
logger.error("Failed to deploy the Noto cash token!");
return false;
}
logger.log("Noto cash token deployed successfully!");
```

**Key Points**:
- **`notary`**: Specifies which verifier (account) can mint new tokens.
- **`restrictMinting`**: If `true`, only the `notary` can mint additional tokens.

---

## Step 2: Mint Tokens

Now that the token contract exists, **mint** an initial supply of tokens to Node1. This step simulates creating new “cash” in the system.

```typescript
logger.log("Step 2: Minting 2000 units of cash to Node1...");
const mintReceipt = await cashToken.mint(verifierNode1, {
to: verifierNode1, // Mint cash to Node1
amount: 2000, // Amount to mint
data: "0x", // Additional data (optional)
});
if (!mintReceipt) {
logger.error("Failed to mint cash tokens!");
return false;
}
logger.log("Successfully minted 2000 units of cash to Node1!");
```

**Key Points**:
- **`amount`**: Number of tokens to create.
- **`data`**: Can include extra metadata or encoding, if needed.

---

## Step 3: Transfer Tokens to Node2

With tokens minted on Node1, you can **transfer** some of them to Node2. This step demonstrates a simple token transfer, much like sending money to another account.

```typescript
logger.log("Step 3: Transferring 1000 units of cash from Node1 to Node2...");
const transferToNode2 = await cashToken.transfer(verifierNode1, {
to: verifierNode2, // Transfer to Node2
amount: 1000, // Amount to transfer
data: "0x", // Optional additional data
});
if (!transferToNode2) {
logger.error("Failed to transfer cash to Node2!");
return false;
}
logger.log("Successfully transferred 1000 units of cash to Node2!");
```

---

## Step 4: Transfer Tokens to Node3

Now let’s see how Node2 can pass tokens to Node3. This step involves calling `.using(paladinClientNode2)` so that **Node2** signs the transaction rather than Node1.

```typescript
logger.log("Step 4: Transferring 800 units of cash from Node2 to Node3...");
const transferToNode3 = await cashToken.using(paladinClientNode2).transfer(verifierNode2, {
to: verifierNode3, // Transfer to Node3
amount: 800, // Amount to transfer
data: "0x", // Optional additional data
});
if (!transferToNode3) {
logger.error("Failed to transfer cash to Node3!");
return false;
}
logger.log("Successfully transferred 800 units of cash to Node3!");
```

**Key Points**:
- **`.using(paladinClientNode2)`** ensures the transaction is signed by Node2.
- If Node2 does not have sufficient tokens (e.g., tries to transfer 1200 while only having 1000), the transfer should fail and return an error.

---

## Conclusion

Congratulations! You’ve successfully:

1. **Deployed a Noto token** to represent cash within the Paladin network.
2. **Minted tokens** from a designated notary account.
3. **Transferred tokens** between different nodes, demonstrating how digital assets move across participants.

At this point, you have a basic grasp of how to issue and manage tokens using the Noto domain.

---

## Next Steps

Now that you’ve explored how to create, mint, and transfer tokens using the Noto domain, you’re ready to delve into Zeto, Paladin’s zero-knowledge domain for more advanced privacy features. In the next tutorial, you’ll learn how to build a cash payment solution—for example, a wholesale CBDC or a commercial bank money rail—while leveraging powerful privacy techniques such as private minting and selective disclosure.

[Continue to the Zero-Knowledge Proof Tutorial →](./zkp-cbdc.md)

Loading

0 comments on commit b26d701

Please sign in to comment.