-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add HelloWorld example with Solidity contract and TypeScript integration
Signed-off-by: dwertent <[email protected]>
- Loading branch information
Showing
50 changed files
with
3,004 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
Oops, something went wrong.