# Building Smart Contracts With Partisia Blockchain

By [ronnakamoto.eth](https://paragraph.com/@ronnakamoto) · 2023-01-03

---

Today, I want to show how easy it is to build smart contracts on the upcoming Layer 1(and Layer 2. It’s a hybrid) blockchain called Partisia Blockchain. This is my first post on a series of posts I plan to do on Partisia Blockchain.

Partisia Blockchain(hereafter referred to as PBC) offers Zero-Knowledge computations(zk-Computation, specifically Secure Multiparty Computation, a.k.a MPC ) on-chain, off-chain and inter-chain. For those who don’t know what Zero-Knowledge is, I have also added a primer on that in this post.

Recently, there has been a great interest in Zero-Knowledge Proofs(ZKP) in the blockchain industry, with several players bringing in new ways to build ZKP-based Decentralized Applications(dApps). This has also led to the creation of ZK-based Virtual Machines(zkVMs).

Zero-Knowledge Proofs Primer
----------------------------

ZKP is a way to prove the validity of a statement(secret) without revealing any information about the statement(secret) itself.

![Two parties involved in ZKP - Prover and Verifier](https://storage.googleapis.com/papyrus_images/cd19538656397be598fac45abc26e6ccd7cffa156edaa56695121b9ef9c61520.png)

Two parties involved in ZKP - Prover and Verifier

In ZKPs, we often have two actors - The prover and the Verifier. The Prover is the one who holds the secret, and Verifier is the one who validates the proof and tells whether it is valid or not. The implications of this are enormous.

Consider an example where you are supposed to prove that you are not from the US as part of KYC to a service provider(maybe an ICO or a new Centralized Exchange). Instead of sending a copy of your government-provided ID, you could generate mathematical proof that the service provider can easily verify.

This process of not revealing zero details about the information being exchanged is why the protocol is known as Zero-Knowledge.

ZKP In Blockchain - Verifiable Computation
------------------------------------------

Verifiable Computation in the context of blockchains is the process of off-loading certain computations to off-chain systems that later returns the result along with proof of valid computation.

Using Verifiable Computations, layer 1 protocols like Ethereum can offload computations to off-chain systems like Layer 2 or sidechains. These off-chain systems submit the computation result and the proof to the on-chain state. For layer 1, like Ethereum, to trust these computations, valid proof is required, which can be used to update the state of Ethereum without re-executing the offloaded transactions.

The off-chain systems that execute the transactions on their off-chain nodes use ZKP to generate these _Validity Proofs_ that prove the correctness of the off-chain execution.

Examples of such systems are ZK Rollup systems like StarkNet, zkSync, and Polygon Zero(earlier known as Mir Protocol).

Zero Knowledge Computation
--------------------------

Traditionally, to perform computation on encrypted data, we have to decrypt it. But, with the help of specific cryptographic techniques, we can perform computations on top of encrypted data without decrypting them. This technique is called **ZK Computation**.

Public-Key Cryptography has helped us transmit and store data securely, but it doesn’t support computation on encrypted data. This is extremely important in this era of a cloud-first mindset.

ZK Computation techniques like _Fully Homomorphic Encryption_(FHE) and _Functional Encryption_ help deal with this.

Consider a common situation when an online business owner wants to clean spam emails from his email list(leads). Usually, such a user uploads his email list to a service provider that performs the filtering process on its server. What most people never think about is the privacy of the email list that just got uploaded for filtering. The emails are now accessible to the service provider, and the user must trust the service provider to deal with the customer data safely.

![A user making use of Functional Encryption to have privacy-preserving email filtering](https://storage.googleapis.com/papyrus_images/e77258c59a115a5a241c411ddc54334201e7c0277688a61c7e0b03baad6883aa.png)

A user making use of Functional Encryption to have privacy-preserving email filtering

Using Functional Encryption, the service provider can perform filtering on encrypted email list data without the need for decrypting the entire data.

Now, consider a situation where there is a need to do ZK computation on a distributed setup involving multiple users/nodes. The type of ZK Computation that can help with this is **Secure Multi-Party Computation**(sMPC/MPC).

An example of sMPC is the sharing of the total amount to invest in an ICO(Initial Coin Offering) among a group without revealing the individual investment of the parties involved.

Assume that 3 friends - Vinny, Uros and Yoshi want to calculate how much they are willing to invest in an ICO together such that they don’t want to reveal individual investments they would make among themselves or to any trusted third party.

Let’s say that Vinny decides to invest $100,000 while Uros and Yoshi decide to go with $50,000 and $10,000, respectively. sMPC makes use of a cryptographic technique known as **_Additive Secret Sharing_**, which allows a user to split their secret into multiple tiny pieces of data that can be shared with others.

In the case of our example, let’s assume that using Additive Secret Sharing, the 3 friends decided to split each of their investments as follows randomly:

![Shows the random secrets distributed among participants](https://storage.googleapis.com/papyrus_images/3cab7ff1b75f40767d71a94d0a6e496270d55066beba350e043a229da9b60169.png)

Shows the random secrets distributed among participants

In the table above, Vinny has split his $100,000 secret into 3 random secrets that add up to $100,000. And he has kept one share(18191) and distributed the other 2 shares to Uros(31,339) and Yoshi(50,470). Note that Vinny’s shared secrets are denoted in red colour.

Similarly, Uros has split his secret into three - 19476(shared with Vinny), 11990(kept himself) and 18534(shared with Yoshi). Yoshi’s 10,000 was split into 5191(shared with Vinny), 2642(shared with Uros) and 2167(kept himself).

When the secret sharing is done, all three participants hold secret slices from each. The critical fact is that each secret slice alone doesn’t yield any helpful information, but the different slices from all three together are useful.

![Shows privacy zones of each party and their partial result](https://storage.googleapis.com/papyrus_images/2b648f28ec52fda0281ebdf64353eeb58d836891e8510781e65ebfe0ef291f0c.png)

Shows privacy zones of each party and their partial result

As shown above, each participant can compute a _Partial Result_ by adding the secret slices they have in their Privacy Zone. Once the partial results are there, the participants can combine these partial results to find the total investment. In the example above, we combine the partial results of Vinny(42858), Uros(45971) and Yoshi(71171) to get $160,000.

If we think about this, we understand that every privacy zone has a partial result, but none of them knows what the other party would invest. Yet, they could compute the total amount they were willing to invest for the ICO.

ZK Computation In Partisia Blockchain
-------------------------------------

Partisia Blockchain is a perfect match made between blockchain and ZK Computation with a focus on Multi-Party Computation(MPC).

The ZK Computations are performed by a network of nodes in Partisia known as the **_ZK Nodes_**. At the core of the Partisia Blockchain solution, there are 3 categories of nodes:

*   **Baker Nodes** - Core network nodes that deal with the underlying P2P mechanism, Consensus, basic transaction handling and block production
    
*   **ZK Nodes** - Nodes that deal with the ZK Computation
    
*   **Oracle Nodes** - Nodes that deal with moving the data and blockchain-agnostic cross-chain transactions via Bring Your Own Coin(BYOC) mechanism
    

In PBC, the MPC is performed using **_Delegated ZK Computation_**. In this mechanism, the ZK computation is delegated to a set of trusted ZK Nodes.

![Shows the trust model of delegated ZK computation](https://storage.googleapis.com/papyrus_images/cb8211507ea9be07a73e211f5c6cc2abee57a12904f66a28dfc9d5c07942d52b.png)

Shows the trust model of delegated ZK computation

In a Delegated ZK Computation, a.k.a Delegated Trust Model for ZK Computation, as depicted in the diagram above, a strong trust system can be achieved by incorporating trusted accredited ZK Nodes and having an incentive mechanism on top of it. This is how PBC handles the delegated ZK computation.

This is a high-level view of how PBC would deal with ZK Computation. But, PBC could accommodate a variety of trust models other than what I just described. For example, a trust model wherein a threshold could be defined such that _X_ number of ZK Nodes from a pool of _Y_ ZK Nodes could be malicious yet yield a secure computation result, where X and Y could be any arbitrary number.

One of the questions that might come up in your mind is how PBC could deal with CPU-intensive computations that usually require a pre-processing step. Well, PBC has some complex protocols that help with such pre-processing by using the Baker Nodes while retaining the security of the computation.

![Show computation that makes use of pre-processed data via oblivious transfer](https://storage.googleapis.com/papyrus_images/7c3ba5e3a3de3cd181eee60ee2f030c9627a2fce5e145841cc28e07857f3058b.png)

Show computation that makes use of pre-processed data via oblivious transfer

As shown in the diagram above, a set of Baker Nodes perform the pre-processing and sends it over to the ZK Nodes for ZK Computation via **Oblivious Transfer Protocol**. **Oblivious Transfer**(OT) is a cryptographic technique by which the sender sends data to a receiver but never knows what data was sent or received.

PBC allows flexible customization for the trust models. For instance, it allows us to choose the ZK Nodes based on region or jurisdiction. This could find application when we are concerned about keeping computations in specific Zk Nodes in specific jurisdictions like Asia, Europe, etc.

The PBC Stack
-------------

Much like how we have tech stacks for full-stack development like MERN(MongoDB+ ExpressJS + ReactJS + NodeJS), MEAN(MongoDB+ ExpressJS + Angular + NodeJS), etc., in blockchain, we have the stack of tech to help us build our solutions.

PBC's stack consists of seven different components, together named **ZEUS**.

![PBC Stack - ZEUS](https://storage.googleapis.com/papyrus_images/be1fb342a432d91ccdd871abacc1ee882f17482c549ed2b7907f8c664d8dfb82.png)

PBC Stack - ZEUS

Smart Contracts In PBC
----------------------

I discussed the underlying concepts that would help you get started with PBC. But, the main intention of this post is to help you start building Decentralized Applications(dApps) on top of PBC leveraging its smart contracts.

Smart Contracts were initially created back in the early 1990s by Nick Szabo, who defined them as follows:

> A set of promises, specified in digital form, including protocols within which the parties perform on these promises

Fast-forward to today, in the age of blockchains; they are the programs that are executed on-chain. Unlike most other popular blockchains, PBC allows you to have a privacy layer on top of its blockchain optionally. This is made possible via its smart contracts.

![Types of smart contracts in PBC](https://storage.googleapis.com/papyrus_images/4cfb2857920763d60362171646aa0d4f209024ead7661cd425d25b21656c40c7.png)

Types of smart contracts in PBC

PBC has three different types of Smart Contracts:

*   **System Smart Contracts** - The core permanent contracts that maintain the PBC ecosystem. They deal with things like the maintenance of public and private smart contracts, help in block production and are involved in pre-processing of ZK computation.
    
*   **Public Smart Contracts** - They are the ones written in PBC smart contract language that is based on Rust. This is the normal type of contract(state and associated actions/methods) we see in blockchains like Ethereum.
    
*   **Private Smart Contracts** - They allow us to do ZK Computations using the privacy layer of PBC
    

As I described in the PBC Stack section, PBC’s smart contract tooling is **Apollo**. The unified approach In Apollo means that, as developers, we have a single, smart contract language(based on Rust) that can help us build public and private smart contracts.

In this post, I’ll explain how we can build public and private smart contracts on PBC. Before we start with the actual coding part, let’s prepare the prerequisites for development.

Prerequisites For Development
-----------------------------

The prerequisites are:

*   Rust Compiler
    
*   Git
    
*   Java Runtime
    
*   Wasm target for Rust
    
*   `cargo-partisia-contract` Cargo Subcommand
    
*   [Partisia Blockchain Wallet](https://chrome.google.com/webstore/detail/partisia-wallet/gjkdbeaiifkpoencioahhcilildpjhgh)
    

The smart contract programming language for PBC is based on [Rust](https://www.rust-lang.org/). If you are unfamiliar with Rust, head to [Rust Lang Website](https://www.rust-lang.org/learn) to learn the basics.

Rust is a modern, high-performance and reliable programming language that has been voted the [most loved programming language](https://survey.stackoverflow.co/2022) for the past seven years.

Rust supports multiple platforms, a.k.a targets. The official Rust team maintains some of these targets, while the community maintains some. Web Assembly is a target that is maintained by the community, and support for it can be added via:

    rustup target add wasm32-unknown-unknown
    

PBC contracts are compiled to Web Assembly code(wasm). So, the above command has to be run after you have Rust installed on your system.

The ZK/Private Contracts require the Java SDK, and this can be installed from [OpenJDK website](https://openjdk.org/). If you are on Mac like me, then you can install it via Homebrew:

    brew install openjdk@17
    

We build smart contract projects using a cargo subcommand called `cargo-partisia-contract`. Cargo Subcommands are a way to extend Cargo(Rust’s build system and package manager) such that we can install them via `cargo install cargo-<subcommand name>`. To install the cargo-partisia-contract subcommand, do the following:

    cargo install cargo-partisia-contract
    

[Partisia Blockchain Wallet](https://chrome.google.com/webstore/detail/partisia-wallet/gjkdbeaiifkpoencioahhcilildpjhgh) is required to deploy contract and interact with it. You will also need some gas to get started. You have few options to get some free test gas:

*   [Hermes Bridge](https://bridge.mpcexplorer.com/) - Bridge ETH from Ethereum Goerli Testnet to PBC Testnet
    
*   Ask in the [PBC Discord](https://discord.gg/NF8kzky84p)
    

Once you have some testnet gas, you could use the [PBC Faucet](https://testnet.partisiablockchain.com/info/contract/02d7c791bd9dd31a4a1a9fdaa99df7cc8414fd333e) to get more gas.

PBC Smart Contract - Hello World
--------------------------------

Let's create a simple hello world smart contract with PBC and deploy it on testnet to test the waters.

Create a smart contract project using the `cargo-partisia-contract` subcommand.

    cargo partisia-contract new hello-world
    

If it succeeded in creating the project, it should display the following message:

![Success message when contract project creation is successful](https://storage.googleapis.com/papyrus_images/a0dbfb6c8a61ef16b5c5b8f848d8e4115b2223c113df8cd0a8c8eec93af3b813.png)

Success message when contract project creation is successful

A boilerplate code is generated that shows an example smart contract. Let’s replace this default contract with the following that allows user to call a function `greet` that sets the state variable `greeting` to a string that greets the user :

    //! hello-world
    
    #[macro_use]
    extern crate pbc_contract_codegen;
    
    use pbc_contract_common::context::{ContractContext};
    
    
    /// This is the state of the contract which is persisted on chain.
    #[state]
    struct ContractState {
        greeting: String,
    }
    
    impl ContractState {
        fn greet(&mut self, name: &str) {
            self.greeting = "Hello ".to_string() + name;
        }
    }
    
    #[init]
    fn initialize(
        _ctx: ContractContext
    ) -> ContractState {
    
        let state = ContractState {
            greeting: "Hello World".to_string(),
        };
    
        state
    }
    
    #[action(shortname = 0x01)]
    fn greet(
        _context: ContractContext,
        state: ContractState,
        name: String,
    ) -> ContractState {
        assert!(!name.is_empty(), "name must not be empty");
    
        let mut new_state = state;
        new_state.greet(&name);
    
        new_state
    }
    

Notice that the contract has three core parts - **Init**, **State** and **Actions** on top of this state. The use of Rust’s attribute-like procedural [macros](https://doc.rust-lang.org/book/ch19-06-macros.html) indicates these.

*   `#[init]` - This annotation declares that the annotated function code will be run when the contract is deployed. This is similar to the `constructor` function in Ethereum
    
*   `#[state]` - This macro declares that the annotated struct is the top level contract state
    
*   `#[action]` - This optional macro declares that the annotated function can be called by client code or other contracts
    

In the contract above, you can see that the Action macro(`#[action(shortname = 0x01)]`) contains a shortname. This a unique identifier that defaults to an automatically generated one. But, when specific names are required, we can set this to a u32 type via the syntax `#[action(shortname = <short u32 value>)]`. This unsigned 32-bit integer value is encoded via Little Endian Base 128(_LEB128_) into a lowercase zero-padded hex value.

Apart from the macros we see in the example above, PBC comes with additional categories of macros as shown below - **ABI Attribute specific** and **ZK Lifetime Attribute specific**:

![Shows all the currently available list of contract macros](https://storage.googleapis.com/papyrus_images/088b1e1de2c2c770a5ea0d3a282d4e3a33bc537ff63c46b16f0fab0c414fad46.png)

Shows all the currently available list of contract macros

Hello World Contract Breakdown
------------------------------

Let’s unpack the hello world contract we saw earlier.

`pbc_contract_codegen` is a crate that comes with different macros(listed in the image above - ABI Attribute macros and ZK Lifetime Attribute macros) that allows us to annotate different parts of our contract code.

Although the example above imports all macros in the crate via `#[macro_use]`, we could also do the following to explicitly import only the ones required:

    use pbc_contract_codegen::{init, state, action};
    

`ContractContext` from `pbc_contract_common` contains the blockchain state information like:

*   `contract_address` - Address of the contract being called
    
*   `sender` - Sender of the transaction
    
*   `block_time` - Block time
    
*   `block_production_time` - Block production time in milliseconds UTC
    
*   `current_transaction` - Hash of current transaction
    
*   `original_transaction` - Hash of parent transaction, if available
    

Now, let’s have a look at the `ContractState`.

![Shows the contract state snippet](https://storage.googleapis.com/papyrus_images/b6d3b2810b49a7e4fdb266338b23eb177dfc9750e970f00c5a0932def3f48d2e.png)

Shows the contract state snippet

The `state` attribute-like macro annotation is a required one and should be defined only once in a contract. This macro internally derives a `ReadWriteState` trait that comes with serialization and de-serialization functionalities for the state. This means that only fields that have an implementation for this trait can be used in the state. This means floating point data types like `f32` or `f64` can’t be used as they don’t `impl` the `ReadWriteState`.

In the example here, the greet method basically allows user to set a name to the `greeting` message in the contract state. Note that `greeting` is `String` which doesn’t have a direct `impl` of `ReadWriteState` trait.

![Shows internal representation of String in Rust](https://storage.googleapis.com/papyrus_images/35651dd7db4e3160411b3fab4fa55b9c47131b438bf4d6002f07dd80373dab91.png)

Shows internal representation of String in Rust

But, since String is internally represented as a vector of `u8`, which has an `impl` of `ReadWriteState`, it works fine.

Now, let’s look at the `initialize` function which is annotated by the `#[init]` macro.

![Shows the initialize function snippet](https://storage.googleapis.com/papyrus_images/fbd80de23ea6ed621f4961bbe9ff58a8ff67292bfb72374bce2d87b7006a10b7.png)

Shows the initialize function snippet

This is the code that gets executed when the contract is deployed and is similar to the `constructor` function in Ethereum’s Solidity. Here, the function returns `ContractState`. If the contract had interactions with other contracts, then the return type would have been a tuple `(ContractState, Vec<EventGroup>)`.

`EventGroup` is a struct that holds the list of events that represent the way to interact with other contracts along with an optional callback payload data. `EventGroup` is created using `EventGroupBuilder`.

![Shows creation of EventGroup using EventGroupBuilder](https://storage.googleapis.com/papyrus_images/ce3c8c3279013602cc0c428ee27836f65ac94d2e224139ba0c14ff28fdc91ef3.png)

Shows creation of EventGroup using EventGroupBuilder

Notice that `EventGroup` contains the `events`. Each event are the contract interactions(represented by the `Interaction` struct, under the hood). The structure of an `Interaction` is as follows:

*   `dest` - Address of contract to call
    
*   `payload` - Payload to send
    
*   `cost` - The amount of gas to allocate for handling the callback. This is defaulted to `None`, which automatically calculates the amount from the remaining gas
    

Let’s look at the action code now.

![Shows the action snippet](https://storage.googleapis.com/papyrus_images/dadf4e9e2cc48469e9329d9addd99c65c56fd8c3c9bd5e003822e96fd261b7de.png)

Shows the action snippet

The action macro allows us to set a shortname for the function. This is for size optimization. When shortname isn’t given, PBC automatically defaults to a shortname based on the function name. This is done by taking the first four bytes of the SHA256 hash of the function name. In the example,above, the greet function returns the updated `ContractState`. Technically, this could be a tuple of `(ContractState, Vec<EventGroup>)`, similar to what I mentioned in initialize part.

Compiling Contract
------------------

The contract can be compiled using the `partisia-contract` cargo subcommand.

![Shows compiling contract in release mode](https://storage.googleapis.com/papyrus_images/f20ab05ba9954aef7998c30b6dd733237743b6fcf03c4ca14227711ecbfd892d.png)

Shows compiling contract in release mode

Notice that in the above command, we are building the contract in `release` mode. This is the optimized mode for deployment compared to the other default mode - `debug`.

Once the command is run, we should get both the `.wasm` contract as well as the `.abi` file. These should be available in the following path:

![Shows the path to compiled artifacts](https://storage.googleapis.com/papyrus_images/eb781c43e063907cec721060c88ab189036a76ea6f22bd85be05fc119ff33c17.png)

Shows the path to compiled artifacts

Deploying Contract
------------------

We can deploy contracts to a PBC network(testnet or mainnet; we focus on testnet in this post)using the PBC Explorer’s [Deploy Wasm Contract Page](https://testnet.partisiablockchain.com/wallet/upload_wasm).

![Shows the contract deployment page](https://storage.googleapis.com/papyrus_images/0c2f4ffbd5d26a7f6179fb78319a5ff0d84e3e7563f3dabbab894a741847435f.png)

Shows the contract deployment page

In this page, you can click on those buttons to choose the `.wasm` and `.abi` files from the compilation stage.

![Shows the contract deployment submit option when artifacts are chosen](https://storage.googleapis.com/papyrus_images/aa4be8fab2b074abcc6a4987cdd7dac4e0bbde3c781c80a8c4164120d76abce4.png)

Shows the contract deployment submit option when artifacts are chosen

Copy the Deploy gas cost value from the text field as we will use that gas value to perform the deployment.

Now, click on the SUBMIT button to bring up the PBC Wallet confirmation dialog.

![Shows confirmation dialog in PBC wallet](https://storage.googleapis.com/papyrus_images/62ca817fb69e02c0843f531a3f07012833b2cc5508dd2bb99729b9441876a674.png)

Shows confirmation dialog in PBC wallet

Then click on Edit Fee button to update the gas fee to the value copied in the previous step and click on save to confirm the updated value:

![Shows the editing of fee to updated value](https://storage.googleapis.com/papyrus_images/1ed28ed20d6d0ac82621b60dd5532944a01be1d09d40663a28e5b6091d074e25.png)

Shows the editing of fee to updated value

Once you click on the TRANSACT button, the transaction should be submitted to the blockchain, after password confirmation:

![Shows the contract deployed sucessfully](https://storage.googleapis.com/papyrus_images/371087d562121df9bb2a5ceec45172192d552d7a5642537f81c81cfa062126c3.png)

Shows the contract deployed sucessfully

Contract Interaction
--------------------

Once the contract is deployed, you get the contract address(`027d207c3f0a810cc39aa3bdd7a03af3ca7a3630e3` above).

Notice that the last 20 bytes of the transaction hash is same as the last 20 bytes of the contract address.

Addresses in PBC are of four types:

*   User account - Prefix of `0x00`
    
*   System Contract - Prefix of `0x01`
    
*   Public Contract - Prefix of `0x02`
    
*   ZK Contract - Prefix of `0x03`
    

Each address is a combination of the Address Type and a unique 20 bytes identifier that is derived from the hash of the public key of an account.

In the hello world contract we deployed, the contract address is `027d207c3f0a810cc39aa3bdd7a03af3ca7a3630e3`. This address can be decomposed into:

![Shows the Address Type and Address Identifier split](https://storage.googleapis.com/papyrus_images/985b859c502e67744cccdf2432aaf3c5b8ba0c5793f7bf89ad57aff82bef48e1.png)

Shows the Address Type and Address Identifier split

To interact with the deployed contract, click on the contract address in the PBC explorer or search for the contract address.

![Shows the contract interaction page](https://storage.googleapis.com/papyrus_images/a8bcb7bb7f3cace1b9019fe3edf9902f55537ef710b60f802ac6a49b5afe98ff.png)

Shows the contract interaction page

Notice that the initial state is set to what we set in the `initialize` function - `Hello World`.

In the **Contract Interaction** section, you can see the actions available in the contract - `GREET`. Click on that button to initiate an action.

![Shows the action form](https://storage.googleapis.com/papyrus_images/13629cd2380302f5b747d1f1b3f1bb8d721cff86f6061b2a93397922b1dd4293.png)

Shows the action form

Provide a name as shown and click the `SUBMIT` button to trigger the action.

Once the action is successful, you should see an execution success message along with the RPC call data.

![Shows the execution status and the RPC call data](https://storage.googleapis.com/papyrus_images/e1d81da2e21b1e9b459ed949776cd762ead4ae610594525e67a6e4c28ce2a35a.png)

Shows the execution status and the RPC call data

The state should also be updated as shown below:

![Shows the updated state](https://storage.googleapis.com/papyrus_images/f4c1e941e3dc1d56b1bb74648e90261fda39072be687a2f581811769d4a9ef82.png)

Shows the updated state

Conclusion
----------

We have seen how to deploy public smart contracts on PBC. In the upcoming posts, we will see how we can leverage PBC to build and deploy Private/ZK Smart contracts.

The code for this tutorial is available at - [hello-world-pbc](https://github.com/ronnakamoto/hello-world-pbc)

---

*Originally published on [ronnakamoto.eth](https://paragraph.com/@ronnakamoto/building-smart-contracts-with-partisia-blockchain)*
