Creating a custom PSP

This tutorial helps you build a custom Private Solana Program from scratch.
Prefer video? Check out the video tutorial about PSPs here.
If you're new to Light Protocol, we recommend following the quick start tutorial on how to build private payments first.

At a high level, here's what you'll accomplish in this tutorial:
  1. 1.
    Initialize and build a fresh PSP project
  2. 2.
    Customize the PSP to fit your use case
Building PSPs becomes easier if you
  • know how to write simple zk-circuits in circom.
  • have a basic understanding of how anchor works.
If you need any help integrating, join us in our chat room.

1. Setup the PSP project

First, make sure you install the following:
  • Go here to install Rust.
  • Go here to install Solana and then run solana-keygen new to create a keypair at the default location. Light uses this keypair to run your program tests. We also recommend checking out the official Solana developers page.
  • Go here to install Yarn.
Install the Light CLI globally:
# npm
npm install -g @lightprotocol/cli
# yarn
yarn global add @lightprotocol/cli
Then go ahead and initialize a new PSP anywhere in your terminal:
light psp:init firstPSP
This will create a fully-fledged boilerplate project with all you need, including an on-chain program, client, and circuit template for a time-locked token escrow. The project scaffold should look like this:
|- circuits
|- firstPSP.light
|- migrations
|- programs
|- firstPSP
|- src
|- Cargo.toml
|- Xargo.toml
|- tests
|- .gitignore
|- .prettierignore
|- Anchor.toml
|- Cargo.lock
|- Cargo.toml
|- package.json
|- tsconfig.json
Fairly standard. If you've used anchor before, this will seem very familiar. The anchor program in /programs is a generic app verifier template. Since in a PSP the program logic is moved from the on-chain program to the client (the constraints are enforced by the circom circuit at proof generation time), we don't need to worry about the code in /programs for now.
Notice how there's a firstPSP.light file inside the circuit folder. This is macro-circom, which takes the data you specify in the .light file and expands it into a fully fledged circom circuit, including all the boilerplate.

2. Customize the circuit

Let's take a look at the firstPSP.light file: We can see two macro keywords: [instance]. [LightTransaction].
instance defines the "config"; you can set nrAppUtxos to whatever amount of input UTXOs your PSP should allow. publicInputs are whatever constraints you want to be public (e.g. timeslot to check against).
LightTransaction lets you define what data should be stored in the UTXO.
Feel free to adapt the PSP to your liking.

3. Call the PSP from your client

The nuances of building the client are based on your specific use case. We recommend you use the default template client as a starting point! It shows you how to call the relevant user methods, such as createAppUtxo and executeAppUtxo.
Once you're done implementing the client, you're ready to build and deploy your PSP!
We're continuously working to make your experience building Private Solana Programs as easy as possible. We'd love to hear your feedback. Join other Light users and the core devs in our Discord and reach out!