# Learn

## Introduction

## What is PUT?

PUT is an open source project implementing a new, high-performance, permissionless blockchain.&#x20;

## Why PUT?

It is possible for a centralized database to process 710,000 transactions per second on a standard gigabit network if the transactions are, on average, no more than 176 bytes.&#x20;

A centralized database can also replicate itself and maintain high availability without significantly compromising that transaction rate using the distributed system technique known as Optimistic Concurrency Control \[H.T.Kung, J.T.Robinson (1981)].&#x20;

At PUT, we are demonstrating that these same theoretical limits apply just as well to blockchain on an adversarial network.&#x20;

The key ingredient?&#x20;

Finding a way to share time when nodes cannot rely upon one another.&#x20;

Once nodes can rely upon time, suddenly \~40 years of distributed systems research becomes applicable to blockchain!

> Perhaps the most striking difference between algorithms obtained by our method and ones based upon timeout is that using timeout produces a traditional distributed algorithm in which the processes operate asynchronously, while our method produces a globally synchronous one in which every process does the same thing at (approximately) the same time.&#x20;
>
> Our method seems to contradict the whole purpose of distributed processing, which is to permit different processes to operate independently and perform different functions.&#x20;
>
> However, if a distributed system is really a single system, then the processes must be synchronized in some way.&#x20;
>
> Conceptually, the easiest way to synchronize processes is to get them all to do the same thing at the same time.&#x20;
>
> Therefore, our method is used to implement a kernel that performs the necessary synchronization--for example, making sure that two different processes do not try to modify a file at the same time.&#x20;
>
> Processes might spend only a small fraction of their time executing the synchronizing kernel; the rest of the time, they can operate independently--e.g., accessing different files.&#x20;
>
> This is an approach we have advocated even when fault-tolerance is not required.&#x20;
>
> The method's basic simplicity makes it easier to understand the precise properties of a system, which is crucial if one is to know just how fault-tolerant the system is. \[L.Lamport (1984)]

Furthermore, and much to our surprise, it can be implemented using a mechanism that has existed in Bitcoin since day one.&#x20;

The Bitcoin feature is called nLocktime and it can be used to postdate transactions using block height instead of a timestamp.&#x20;

As a Bitcoin client, you would use block height instead of a timestamp if you don't rely upon the network.&#x20;

Block height turns out to be an instance of what's being called a Verifiable Delay Function in cryptography circles.&#x20;

It's a cryptographically secure way to say time has passed. In PUT, we use a far more granular verifiable delay function, a SHA 256 hash chain, to checkpoint the ledger and coordinate consensus.&#x20;

With it, we implement Optimistic Concurrency Control and are now well en route towards that theoretical limit of 710,000 transactions per second.

## Documentation Overview

The PUT docs describe the PUT open source project, a blockchain built from the ground up for scale.&#x20;

They cover why PUT is useful, how to use it, how it works, and why it will continue to work long after the company PUT closes its doors.&#x20;

The goal of the PUT architecture is to demonstrate there exists a set of software algorithms that when used in combination to implement a blockchain, removes software as a performance bottleneck, allowing transaction throughput to scale proportionally with network bandwidth.&#x20;

The architecture goes on to satisfy all three desirable properties of a proper blockchain: it is scalable, secure and decentralized.

The architecture describes a theoretical upper bound of 710 thousand transactions per second (tps) on a standard gigabit network and 28.4 million tps on 40 gigabit.&#x20;

Furthermore, the architecture supports safe, concurrent execution of programs authored in general-purpose programming languages such as C or Rust.

## What is a PUT Cluster?

A cluster is a set of computers that work together and can be viewed from the outside as a single system.&#x20;

A PUT cluster is a set of independently owned computers working together (and sometimes against each other) to verify the output of untrusted, user-submitted programs.&#x20;

A PUT cluster can be utilized any time a user wants to preserve an immutable record of events in time or programmatic interpretations of those events.&#x20;

One use is to track which of the computers did meaningful work to keep the cluster running. Another use might be to track the possession of real-world assets.&#x20;

In each case, the cluster produces a record of events called the ledger. It will be preserved for the lifetime of the cluster.&#x20;

As long as someone somewhere in the world maintains a copy of the ledger, the output of its programs (which may contain a record of who possesses what) will forever be reproducible, independent of the organization that launched it.

## What are PUTs?

A PUT is the name of PUT's native token, which can be passed to nodes in a PUT cluster in exchange for running an on-chain program or validating its output.&#x20;

The system may perform micropayments of fractional PUTs, which are called lamports.&#x20;

They are named in honor of PUT's biggest technical influence, Leslie Lamport.&#x20;

A lamport has a value of 0.000000001 PUT.

## Disclaimer

All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the author's best effort.&#x20;

It is up to the reader to check and validate their accuracy and truthfulness.&#x20;

Furthermore, nothing in this project constitutes a solicitation for investment.


# Introduction to PUT

## Introduction

## What is PUT?

PUT is an open source project implementing a new, high-performance, permissionless blockchain.&#x20;

## Why PUT?

It is possible for a centralized database to process 710,000 transactions per second on a standard gigabit network if the transactions are, on average, no more than 176 bytes.&#x20;

A centralized database can also replicate itself and maintain high availability without significantly compromising that transaction rate using the distributed system technique known as Optimistic Concurrency Control \[H.T.Kung, J.T.Robinson (1981)].&#x20;

At PUT, we are demonstrating that these same theoretical limits apply just as well to blockchain on an adversarial network.&#x20;

The key ingredient?&#x20;

Finding a way to share time when nodes cannot rely upon one another.&#x20;

Once nodes can rely upon time, suddenly \~40 years of distributed systems research becomes applicable to blockchain!

> Perhaps the most striking difference between algorithms obtained by our method and ones based upon timeout is that using timeout produces a traditional distributed algorithm in which the processes operate asynchronously, while our method produces a globally synchronous one in which every process does the same thing at (approximately) the same time.&#x20;
>
> Our method seems to contradict the whole purpose of distributed processing, which is to permit different processes to operate independently and perform different functions.&#x20;
>
> However, if a distributed system is really a single system, then the processes must be synchronized in some way.&#x20;
>
> Conceptually, the easiest way to synchronize processes is to get them all to do the same thing at the same time.&#x20;
>
> Therefore, our method is used to implement a kernel that performs the necessary synchronization--for example, making sure that two different processes do not try to modify a file at the same time.&#x20;
>
> Processes might spend only a small fraction of their time executing the synchronizing kernel; the rest of the time, they can operate independently--e.g., accessing different files.&#x20;
>
> This is an approach we have advocated even when fault-tolerance is not required.&#x20;
>
> The method's basic simplicity makes it easier to understand the precise properties of a system, which is crucial if one is to know just how fault-tolerant the system is. \[L.Lamport (1984)]

Furthermore, and much to our surprise, it can be implemented using a mechanism that has existed in Bitcoin since day one.&#x20;

The Bitcoin feature is called nLocktime and it can be used to postdate transactions using block height instead of a timestamp.&#x20;

As a Bitcoin client, you would use block height instead of a timestamp if you don't rely upon the network.&#x20;

Block height turns out to be an instance of what's being called a Verifiable Delay Function in cryptography circles.&#x20;

It's a cryptographically secure way to say time has passed. In PUT, we use a far more granular verifiable delay function, a SHA 256 hash chain, to checkpoint the ledger and coordinate consensus.&#x20;

With it, we implement Optimistic Concurrency Control and are now well en route towards that theoretical limit of 710,000 transactions per second.

## Documentation Overview

The PUT docs describe the PUT open source project, a blockchain built from the ground up for scale.&#x20;

They cover why PUT is useful, how to use it, how it works, and why it will continue to work long after the company PUT closes its doors.&#x20;

The goal of the PUT architecture is to demonstrate there exists a set of software algorithms that when used in combination to implement a blockchain, removes software as a performance bottleneck, allowing transaction throughput to scale proportionally with network bandwidth.&#x20;

The architecture goes on to satisfy all three desirable properties of a proper blockchain: it is scalable, secure and decentralized.

The architecture describes a theoretical upper bound of 710 thousand transactions per second (tps) on a standard gigabit network and 28.4 million tps on 40 gigabit.&#x20;

Furthermore, the architecture supports safe, concurrent execution of programs authored in general-purpose programming languages such as C or Rust.

## What is a PUT Cluster?

A cluster is a set of computers that work together and can be viewed from the outside as a single system.&#x20;

A PUT cluster is a set of independently owned computers working together (and sometimes against each other) to verify the output of untrusted, user-submitted programs.&#x20;

A PUT cluster can be utilized any time a user wants to preserve an immutable record of events in time or programmatic interpretations of those events.&#x20;

One use is to track which of the computers did meaningful work to keep the cluster running. Another use might be to track the possession of real-world assets.&#x20;

In each case, the cluster produces a record of events called the ledger. It will be preserved for the lifetime of the cluster.&#x20;

As long as someone somewhere in the world maintains a copy of the ledger, the output of its programs (which may contain a record of who possesses what) will forever be reproducible, independent of the organization that launched it.

## What are PUTs?

A PUT is the name of PUT's native token, which can be passed to nodes in a PUT cluster in exchange for running an on-chain program or validating its output.&#x20;

The system may perform micropayments of fractional PUTs, which are called lamports.&#x20;

They are named in honor of PUT's biggest technical influence, Leslie Lamport.&#x20;

A lamport has a value of 0.000000001 PUT.

## Disclaimer

All claims, content, designs, algorithms, estimates, roadmaps, specifications, and performance measurements described in this project are done with the author's best effort.&#x20;

It is up to the reader to check and validate their accuracy and truthfulness.&#x20;

Furthermore, nothing in this project constitutes a solicitation for investment.


# Getting started with PUT

## PUT Wallet Guide

This document describes the different wallet options that are available to users of PUT who want to be able to send, receive and interact with PUT tokens on the PUT blockchain.

## What is a Wallet?

A crypto wallet is a device or application that stores a collection of keys and can be used to send, receive, and track ownership of cryptocurrencies.&#x20;

Wallets can take many forms.&#x20;

A wallet might be a directory or file in your computer's file system, a piece of paper, or a specialized device called a hardware wallet.&#x20;

There are also various smartphone apps and computer programs that provide a user-friendly way to create and manage wallets.

A keypair is a securely generated private key and its cryptographically-derived public key.&#x20;

A private key and its corresponding public key are together known as a keypair.&#x20;

A wallet contains a collection of one or more keypairs and provides some means to interact with them.

The public key (commonly shortened to pubkey) is known as the wallet's receiving address or simply its address.&#x20;

The wallet address may be shared and displayed freely. When another party is going to send some amount of cryptocurrency to a wallet, they need to know the wallet's receiving address.&#x20;

Depending on a blockchain's implementation, the address can also be used to view certain information about a wallet, such as viewing the balance, but has no ability to change anything about the wallet or withdraw any tokens.

The private key is required to digitally sign any transactions to send cryptocurrencies to another address or to make any changes to the wallet.&#x20;

The private key must never be shared. If someone gains access to the private key to a wallet, they can withdraw all the tokens it contains.&#x20;

If the private key for a wallet is lost, any tokens that have been sent to that wallet's address are permanently lost.

Different wallet solutions offer different approaches to keypair security, interacting with the keypair, and signing transactions to use/spend the tokens. Some are easier to use than others.&#x20;

Some store and back up private keys more securely.&#x20;

PUT supports multiple types of wallets so you can choose the right balance of security and convenience.

If you want to be able to receive PUT tokens on the PUT blockchain, you first will need to create a wallet.

## Supported Wallets

Several browser and mobile app based wallets support PUT. Find the right one for you on the PUT Ecosystem page.

For advanced users or developers, the command-line wallets may be more appropriate, as new features on the PUT blockchain will always be supported on the command line first before being integrated into third-party solutions.


# Architecture


# What is a PUT Cluster?

## A PUT Cluster

A PUT cluster is a set of validators working together to serve client transactions and maintain the integrity of the ledger.

Many clusters may coexist.

When two clusters share a common genesis block, they attempt to converge.

Otherwise, they simply ignore the existence of the other.

Transactions sent to the wrong one are quietly rejected.

In this section, we'll discuss how a cluster is created, how nodes join the cluster, how they share the ledger, how they ensure the ledger is replicated, and how they cope with buggy and malicious nodes.

## Creating a Cluster

Before starting any validators, one first needs to create a genesis config.

The config references two public keys, a mint and a bootstrap validator.

The validator holding the bootstrap validator's private key is responsible for appending the first entries to the ledger.

It initializes its internal state with the mint's account.

That account will hold the number of native tokens defined by the genesis config.

The second validator then contacts the bootstrap validator to register as a validator.

Additional validators then register with any registered member of the cluster.

A validator receives all entries from the leader and submits votes confirming those entries are valid.

After voting, the validator is expected to store those entries.

Once the validator observes a sufficient number of copies exist, it deletes its copy.

## Joining a Cluster

Validators enter the cluster via registration messages sent to its control plane.

The control plane is implemented using a gossip protocol, meaning that a node may register with any existing node, and expect its registration to propagate to all nodes in the cluster.

The time it takes for all nodes to synchronize is proportional to the square of the number of nodes participating in the cluster.

Algorithmically, that's considered very slow, but in exchange for that time, a node is assured that it eventually has all the same information as every other node, and that information cannot be censored by any one node.

## Sending Transactions to a Cluster

Clients send transactions to any validator's Transaction Processing Unit (TPU) port.

If the node is in the validator role, it forwards the transaction to the designated leader.

If in the leader role, the node bundles incoming transactions, timestamps them creating an entry, and pushes them onto the cluster's data plane.

Once on the data plane, the transactions are validated by validator nodes, effectively appending them to the ledger.

## Confirming Transactions

A PUT cluster is capable of subsecond confirmation for thousands of nodes with plans to scale up to hundreds of thousands of nodes.

Confirmation times are expected to increase only with the logarithm of the number of validators, where the logarithm's base is very high.

If the base is one thousand, for example, it means that for the first thousand nodes, confirmation will be the duration of three network hops plus the time it takes the slowest validator of a supermajority to vote.

For the next million nodes, confirmation increases by only one network hop.

PUT defines confirmation as the duration of time from when the leader timestamps a new entry to the moment when it recognizes a supermajority of ledger votes.

Scalable confirmation can be achieved using the following combination of techniques:

1.Timestamp transactions with a VDF sample and sign the timestamp.

2.Split the transactions into batches, send each to separate nodes and have each node share its batch with its peers.

3.Repeat the previous step recursively until all nodes have all batches.

PUT rotates leaders at fixed intervals, called slots.

Each leader may only produce entries during its allotted slot. The leader therefore timestamps transactions so that validators may lookup the public key of the designated leader.

The leader then signs the timestamp so that a validator may verify the signature, proving the signer is owner of the designated leader's public key.

Next, transactions are broken into batches so that a node can send transactions to multiple parties without making multiple copies.

If, for example, the leader needed to send 60 transactions to 6 nodes, it would break that collection of 60 into batches of 10 transactions and send one to each node.

This allows the leader to PUT 60 transactions on the wire, not 60 transactions for each node.

Each node then shares its batch with its peers. Once the node has collected all 6 batches, it reconstructs the original set of 60 transactions.

A batch of transactions can only be split so many times before it is so small that header information becomes the primary consumer of network bandwidth.

At the time of this writing (December, 2021), the approach is scaling well up to about 1,250 validators.

To scale up to hundreds of thousands of validators, each node can apply the same technique as the leader node to another set of nodes of equal size.

We call the technique Turbine Block Propagation.


# Clusters


# PUT Clusters

PUT Clusters

PUT maintains several different clusters with different purposes.

Before you begin make sure you have first installed the PUT command line tools

Explorers:

* <https://www.putscan.com/>

## Testnet\#

* Testnet is where the PUT core contributors stress test recent release features on a live cluster, particularly focused on network performance, stability and validator behavior.
* Testnet tokens are not real
* Testnet may be subject to ledger resets.
* Testnet includes a token faucet for airdrops for application testing
* Testnet typically runs a newer software release branch than both Devnet and Mainnet Beta
* Gossip entrypoint for Testnet: entrypoint.testnet.put.com:8001
* Metrics environment variable for Testnet:

```
export PUT_METRICS_CONFIG="host=https://metrics.put.com:8086,db=tds,u=testnet_write,p=c4fa841aa918bf8274e3e2a44d77568d9861b3ea"
```

* RPC URL for Testnet:<https://rpc-test.put.com>

Example put command-line configuration#&#x20;

```
put config set --url https://rpc.put.com
```

&#x20;

Example put-validator command-line#&#x20;

```
$ put-validator
--identity validator-keypair.json
--vote-account vote-account-keypair.json
--known-validator 5D1fNXzvv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on
--known-validator dDzy5SR3AXdYWVqbDEkVFdvSPCtS9ihF5kJkHCtXoFs
--known-validator Ft5fbkqNa76vnsjYNwjDZUXoTWpP7VYm3mtsaQckQADN
--known-validator eoKpUABi59aT4rR9HGS3LcMecfut9x7zJyodWWP43YQ
--known-validator 9QxCLckBiJc783jnMvXZubK4wH86Eqqvashtrwvcsgkv
--only-known-rpc
--ledger ledger
--rpc-port 8899
--dynamic-port-range 8000-8020
--entrypoint entrypoint.testnet.put.com:8001
--entrypoint entrypoint2.testnet.put.com:8001
--entrypoint entrypoint3.testnet.put.com:8001
--expected-genesis-hash 4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY
--wal-recovery-mode skip_any_corrupted_record
--limit-ledger-size
```

The identities of the --known-validators are:

* `5D1fNXzvv5NjV1ysLjirC4WY92RNsVH18vjmcszZd8on` - Solana Labs
* `dDzy5SR3AXdYWVqbDEkVFdvSPCtS9ihF5kJkHCtXoFs` - MonkeDAO
* `Ft5fbkqNa76vnsjYNwjDZUXoTWpP7VYm3mtsaQckQADN` - Certus One
* `eoKpUABi59aT4rR9HGS3LcMecfut9x7zJyodWWP43YQ` - SerGo
* `9QxCLckBiJc783jnMvXZubK4wH86Eqqvashtrwvcsgkv` - Algo|Stake

## Mainnet Beta

A permissionless, persistent cluster for PUT users, builders, validators and token holders.

* Tokens that are issued on Mainnet Beta are **real** PUT
* Gossip entrypoint for Mainnet Beta: `entrypoint.mainnet-beta.put.com:8001`
* Metrics environment variable for Mainnet Beta:

```
export PUT_METRICS_CONFIG="host=https://metrics.put.com:8086,db=mainnet-beta,u=mainnet-beta_write,p=password"
```

* RPC URL for Mainnet Beta: [`https://rpc-test.put.com`](https://rpc-test.put.com)

Example put command-line configuration#&#x20;

```
put config set --url https://rpc-test.put.com
```

Example put-validator command-line#&#x20;

```
$ put-validator
--identity ~/validator-keypair.json
--vote-account ~/vote-account-keypair.json
--known-validator 7Np41oeYqPefeNQEHSv1UDhYrehxin3NStELsSKCT4K2
--known-validator GdnSyH3YtwcxFvQrVVJMm1JhTS4QVX7MFsX56uJLUfiZ
--known-validator DE1bawNcRJB9rVm3buyMVfr8mBEoyyu73NBovf2oXJsJ
--known-validator CakcnaRDHka2gXyfbEd2d3xsvkJkqsLw2akB3zsN1D2S
--only-known-rpc
--ledger ledger
--rpc-port 8899
--private-rpc
--dynamic-port-range 8000-8020
--entrypoint entrypoint.mainnet-beta.put.com:8001
--entrypoint entrypoint2.mainnet-beta.put.com:8001
--entrypoint entrypoint3.mainnet-beta.put.com:8001
--entrypoint entrypoint4.mainnet-beta.put.com:8001
--entrypoint entrypoint5.mainnet-beta.put.com:8001
--expected-genesis-hash 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
--wal-recovery-mode skip_any_corrupted_record
--limit-ledger-size 
```

All four --known-validators are operated by Put Labs


# RPC Endpoints

## PUT Cluster RPC Endpoints

PUT maintains dedicated api nodes to fulfill JSON-RPC requests for each public cluster, and third parties may as well.&#x20;

Here are the public RPC endpoints currently available and recommended for each public cluster:&#x20;

## Testnet&#x20;

## Endpoint

* [https://rpc.put.com](<https://rpc.put.com&#xD;&#xA;>)

## Rate Limits

* Maximum number of requests per 10 seconds per IP: 100
* Maximum number of requests per 10 seconds per IP for a single RPC: 40
* Maximum concurrent connections per IP: 40
* Maximum connection rate per 10 seconds per IP: 40
* Maximum amount of data per 30 second: 100 MB

## Mainnet Beta

## Endpoints\*

* <https://rpc-test.put.com> - PUT-hosted api node cluster, backed by a load balancer; rate-limited

## Rate Limits

* Maximum number of requests per 10 seconds per IP: 100
* Maximum number of requests per 10 seconds per IP for a single RPC: 40
* Maximum concurrent connections per IP: 40
* Maximum connection rate per 10 seconds per IP: 40
* Maximum amount of data per 30 second: 100 MB

\*The public RPC endpoints are not intended for production applications.&#x20;

Please use dedicated/private RPC servers when you launch your application, drop NFTs, etc.

&#x20;The public services are subject to abuse and rate limits may change without prior notice.&#x20;

Likewise, high-traffic websites may be blocked without prior notice.&#x20;

## Common HTTP Error Codes

* 403 -- Your IP address or website has been blocked. It is time to run your own RPC server(s) or find a private service.
* 429 -- Your IP address is exceeding the rate limits. Slow down! Use the Retry-After HTTP response header to determine how long to wait before making another request.


# Benchmark a Cluster

## Benchmark a Cluster

The PUT git repository contains all the scripts you might need to spin up your own local testnet.&#x20;

Depending on what you're looking to achieve, you may want to run a different variation, as the full-fledged, performance-enhanced multinode testnet is considerably more complex to set up than a Rust-only, singlenode testnode.&#x20;

If you are looking to develop high-level features, such as experimenting with smart contracts, save yourself some setup headaches and stick to the Rust-only singlenode demo.

&#x20;If you're doing performance optimization of the transaction pipeline, consider the enhanced singlenode demo.&#x20;

If you're doing consensus work, you'll need at least a Rust-only multinode demo. If you want to reproduce our TPS metrics, run the enhanced multinode demo.

For all four variations, you'd need the latest Rust toolchain and the PUT source code:

First, setup Rust, Cargo and system packages as described in the PUT README

Now checkout the code from github:&#x20;

```
git clone https://github.com/put-labs/put.git 
cd put
```

The demo code is sometimes broken between releases as we add new low-level features, so if this is your first time running the demo, you'll improve your odds of success if you check out the latest release before proceeding:&#x20;

```
TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
 
git checkout $TAG 
```

## Configuration Setup

Ensure important programs such as the vote program are built before any nodes are started.&#x20;

Note that we are using the release build here for good performance.&#x20;

If you want the debug build, use just cargo build and omit the NDEBUG=1 part of the command.&#x20;

```
cargo build --release
```

The network is initialized with a genesis ledger generated by running the following script.&#x20;

```
NDEBUG=1 ./multinode-demo/setup.sh 
```

## Faucet

In order for the validators and clients to work, we'll need to spin up a faucet to give out some test tokens.&#x20;

The faucet delivers Milton Friedman-style "air drops" (free tokens to requesting clients) to be used in test transactions.

Start the faucet with:&#x20;

```
NDEBUG=1 ./multinode-demo/faucet.sh 
```

Singlenode Testnet#

Before you start a validator, make sure you know the IP address of the machine you want to be the bootstrap validator for the demo, and make sure that udp ports 8000-10000 are open on all the machines you want to test with.

Now start the bootstrap validator in a separate shell:&#x20;

```
NDEBUG=1 ./multinode-demo/bootstrap-validator.sh
```

Wait a few seconds for the server to initialize. It will print "leader ready..." when it's ready to receive transactions.&#x20;

The leader will request some tokens from the faucet if it doesn't have any. The faucet does not need to be running for subsequent leader starts.&#x20;

## Multinode Testnet

To run a multinode testnet, after starting a leader node, spin up some additional validators in separate shells:&#x20;

```
NDEBUG=1 ./multinode-demo/validator-x.sh
```

To run a performance-enhanced validator on Linux, CUDA 10.0 must be installed on your system:&#x20;

```
./fetch-perf-libs.sh 
NDEBUG=1 PUT_CUDA=1 ./multinode-demo/bootstrap-validator.sh 
NDEBUG=1 PUT_CUDA=1 ./multinode-demo/validator.sh 
```

## Testnet Client Demo

Now that your singlenode or multinode testnet is up and running let's send it some transactions!

In a separate shell start the client:&#x20;

```
NDEBUG=1 ./multinode-demo/bench-tps.sh # runs against localhost by default
```

What just happened? The client demo spins up several threads to send 500,000 transactions to the testnet as quickly as it can.&#x20;

The client then pings the testnet periodically to see how many transactions it processed in that time.&#x20;

Take note that the demo intentionally floods the network with UDP packets, such that the network will almost certainly drop a bunch of them.&#x20;

This ensures the testnet has an opportunity to reach 710k TPS. The client demo completes after it has convinced itself the testnet won't process any additional transactions.&#x20;

You should see several TPS measurements printed to the screen. In the multinode variation, you'll see TPS measurements for each validator node as well.&#x20;

## Testnet Debugging

There are some useful debug messages in the code, you can enable them on a per-module and per-level basis. Before running a leader or validator set the normal RUST\_LOG environment variable.

For example

* To enable info everywhere and debug only in the put::banking\_stage module:

```
export RUST_LOG=put=info,put::banking_stage=debug
```

* To enable BPF program logging:&#x20;

```
export RUST_LOG=put_bpf_loader=trace
```

Generally we are using debug for infrequent debug messages, trace for potentially frequent messages and info for performance-related logging.

You can also attach to a running process with GDB.&#x20;

The leader's process is named put-validator:&#x20;

```
sudo gdb 
attach <PID>
set logging on 
thread apply all bt
```

This will dump all the threads stack traces into gdb.txt&#x20;

## Developer Testnet

In this example the client connects to our public testnet. To run validators on the testnet you would need to open udp ports 8000-10000.&#x20;

```
NDEBUG=1 ./multinode-demo/bench-tps.sh --entrypoint entrypoint.devnet.put.com:8001 --faucet api.devnet.put.com:9900 --duration 60 --tx_count 50
```

You can observe the effects of your client's transactions on our metrics dashboard


# Performance Metrics

## Performance Metrics

PUT cluster performance is measured as average number of transactions per second that the network can sustain (TPS).&#x20;

And, how long it takes for a transaction to be confirmed by super majority of the cluster (Confirmation Time).

Each cluster node maintains various counters that are incremented on certain events.&#x20;

These counters are periodically uploaded to a cloud based database.&#x20;

PUT's metrics dashboard fetches these counters, and computes the performance metrics and displays it on the dashboard.&#x20;

## TPS

Each node's bank runtime maintains a count of transactions that it has processed.&#x20;

The dashboard first calculates the median count of transactions across all metrics enabled nodes in the cluster.&#x20;

The median cluster transaction count is then averaged over a 2 second period and displayed in the TPS time series graph.&#x20;

The dashboard also shows the Mean TPS, Max TPS and Total Transaction Count stats which are all calculated from the median transaction count.&#x20;

## Confirmation Time

Each validator node maintains a list of active ledger forks that are visible to the node.&#x20;

A fork is considered to be frozen when the node has received and processed all entries corresponding to the fork.&#x20;

A fork is considered to be confirmed when it receives cumulative super majority vote, and when one of its children forks is frozen.

The node assigns a timestamp to every new fork, and computes the time it took to confirm the fork.&#x20;

This time is reflected as validator confirmation time in performance metrics.&#x20;

The performance dashboard displays the average of each validator node's confirmation time as a time series graph.&#x20;

## Hardware setup

The validator software is deployed to GCP n1-standard-16 instances with 1TB pd-ssd disk, and 2x Nvidia V100 GPUs. These are deployed in the us-west-1 region.

PUT-bench-tps is started after the network converges from a client machine with n1-standard-16 CPU-only instance with the following arguments:

&#x20;\--tx\_count=50000 --thread-batch-sleep 1000

TPS and confirmation metrics are captured from the dashboard numbers over a 5 minute average of when the bench-tps transfer stage begins.


# Consensus


# Synchronization

## Synchronization&#x20;

Fast, reliable synchronization is the biggest reason PUT is able to achieve such high throughput.&#x20;

Traditional blockchains synchronize on large chunks of transactions called blocks.&#x20;

By synchronizing on blocks, a transaction cannot be processed until a duration, called "block time", has passed.&#x20;

In Proof of Work consensus, these block times need to be very large (\~10 minutes) to minimize the odds of multiple validators producing a new valid block at the same time.&#x20;

There's no such constraint in Proof of Stake consensus, but without reliable timestamps, a validator cannot determine the order of incoming blocks.&#x20;

The popular workaround is to tag each block with a wallclock timestamp.

&#x20;Because of clock drift and variance in network latencies, the timestamp is only accurate within an hour or two.&#x20;

To workaround the workaround, these systems lengthen block times to provide reasonable certainty that the median timestamp on each block is always increasing.&#x20;

PUT takes a very different approach, which it calls Proof of History or PoH.&#x20;

Leader nodes "timestamp" blocks with cryptographic proofs that some duration of time has passed since the last proof.&#x20;

All data hashed into the proof most certainly have occurred before the proof was generated.&#x20;

The node then shares the new block with validator nodes, which are able to verify those proofs.&#x20;

The blocks can arrive at validators in any order or even could be replayed years later.&#x20;

With such reliable synchronization guarantees, PUT is able to break blocks into smaller batches of transactions called entries.

&#x20;Entries are streamed to validators in realtime, before any notion of block consensus.&#x20;

PUT technically never sends a block, but uses the term to describe the sequence of entries that validators vote on to achieve confirmation.&#x20;

In that way, PUT's confirmation times can be compared apples to apples to block-based systems.&#x20;

The current implementation sets block time to 800ms.&#x20;

What's happening under the hood is that entries are streamed to validators as quickly as a leader node can batch a set of valid transactions into an entry.&#x20;

Validators process those entries long before it is time to vote on their validity.&#x20;

By processing the transactions optimistically, there is effectively no delay between the time the last entry is received and the time when the node can vote.&#x20;

In the event consensus is not achieved, a node simply rolls back its state.&#x20;

This optimisic processing technique was introduced in 1981 and called Optimistic Concurrency Control.&#x20;

It can be applied to blockchain architecture where a cluster votes on a hash that represents the full ledger up to some block height.&#x20;

In PUT, it is implemented trivially using the last entry's PoH hash.&#x20;

## Relationship to VDFs&#x20;

The Proof of History technique was first described for use in blockchain by PUT in November of 2017.&#x20;

In June of the following year, a similar technique was described at Stanford and called a verifiable delay function or VDF.&#x20;

A desirable property of a VDF is that verification time is very fast.&#x20;

PUT's approach to verifying its delay function is proportional to the time it took to create it.&#x20;

Split over a 4000 core GPU, it is sufficiently fast for PUT's needs, but if you asked the authors of the paper cited above, they might tell you (and have) that PUT's approach is algorithmically slow and it shouldn't be called a VDF.&#x20;

We argue the term VDF should represent the category of verifiable delay functions and not just the subset with certain performance characteristics.&#x20;

Until that's resolved, PUT will likely continue using the term PoH for its application-specific VDF.&#x20;

Another difference between PoH and VDFs is that a VDF is used only for tracking duration.&#x20;

PoH's hash chain, on the other hand, includes hashes of any data the application observed. That data is a double-edged sword.&#x20;

On one side, the data "proves history" - that the data most certainly existed before hashes after it.&#x20;

On the other side, it means the application can manipulate the hash chain by changing when the data is hashed.&#x20;

The PoH chain therefore does not serve as a good source of randomness whereas a VDF without that data could.&#x20;

PUT's leader rotation algorithm, for example, is derived only from the VDF height and not its hash at that height.&#x20;

## Relationship to Consensus Mechanisms

Proof of History is not a consensus mechanism, but it is used to improve the performance of PUT's Proof of Stake consensus.&#x20;

It is also used to improve the performance of the data plane protocols.&#x20;

## More on Proof of History&#x20;

* water clock analogy&#x20;
* Proof of History overview


# Leader Rotation

## Leader Rotation

At any given moment, a cluster expects only one validator to produce ledger entries.&#x20;

By having only one leader at a time, all validators are able to replay identical copies of the ledger.&#x20;

The drawback of only one leader at a time, however, is that a malicious leader is capable of censoring votes and transactions.&#x20;

Since censoring cannot be distinguished from the network dropping packets, the cluster cannot simply elect a single node to hold the leader role indefinitely.&#x20;

Instead, the cluster minimizes the influence of a malicious leader by rotating which node takes the lead.

Each validator selects the expected leader using the same algorithm, described below.&#x20;

When the validator receives a new signed ledger entry, it can be certain that an entry was produced by the expected leader.&#x20;

The order of slots which each leader is assigned a slot is called a leader schedule.

## Leader Schedule Rotation

A validator rejects blocks that are not signed by the slot leader.&#x20;

The list of identities of all slot leaders is called a leader schedule. The leader schedule is recomputed locally and periodically.&#x20;

It assigns slot leaders for a duration of time called an epoch.&#x20;

The schedule must be computed far in advance of the slots it assigns, such that the ledger state it uses to compute the schedule is finalized.&#x20;

That duration is called the leader schedule offset.&#x20;

PUT sets the offset to the duration of slots until the next epoch.&#x20;

That is, the leader schedule for an epoch is calculated from the ledger state at the start of the previous epoch.&#x20;

The offset of one epoch is fairly arbitrary and assumed to be sufficiently long such that all validators will have finalized their ledger state before the next schedule is generated.&#x20;

A cluster may choose to shorten the offset to reduce the time between stake changes and leader schedule updates.

While operating without partitions lasting longer than an epoch, the schedule only needs to be generated when the root fork crosses the epoch boundary.&#x20;

Since the schedule is for the next epoch, any new stakes committed to the root fork will not be active until the next epoch.&#x20;

The block used for generating the leader schedule is the first block to cross the epoch boundary.

Without a partition lasting longer than an epoch, the cluster will work as follows:

1. A validator continuously updates its own root fork as it votes.
2. The validator updates its leader schedule each time the slot height crosses an epoch boundary.

For example:

Let's assume an epoch duration of 100 slots, which in reality is magnitudes higher.&#x20;

The root fork is updated from fork computed at slot height 99 to a fork computed at slot height 102. Forks with slots at height 100, 101 were skipped because of failures.&#x20;

The new leader schedule is computed using fork at slot height 102. It is active from slot 200 until it is updated again.

No inconsistency can exist because every validator that is voting with the cluster has skipped 100 and 101 when its root passes 102.&#x20;

All validators, regardless of voting pattern, would be committing to a root that is either 102, or a descendant of 102.

Leader Schedule Rotation with Epoch Sized Partitions.#

The duration of the leader schedule offset has a direct relationship to the likelihood of a cluster having an inconsistent view of the correct leader schedule.

Consider the following scenario:

Two partitions that are generating half of the blocks each. Neither is coming to a definitive supermajority fork.&#x20;

Both will cross epoch 100 and 200 without actually committing to a root and therefore a cluster-wide commitment to a new leader schedule.

In this unstable scenario, multiple valid leader schedules exist.

* A leader schedule is generated for every fork whose direct parent is in the previous epoch.
* The leader schedule is valid after the start of the next epoch for descendant forks until it is updated.

Each partition's schedule will diverge after the partition lasts more than an epoch.&#x20;

For this reason, the epoch duration should be selected to be much much larger then slot time and the expected length for a fork to be committed to root.

After observing the cluster for a sufficient amount of time, the leader schedule offset can be selected based on the median partition duration and its standard deviation.

&#x20;For example, an offset longer then the median partition duration plus six standard deviations would reduce the likelihood of an inconsistent ledger schedule in the cluster to 1 in 1 million.

## Leader Schedule Generation at Genesis

The genesis config declares the first leader for the first epoch.&#x20;

This leader ends up scheduled for the first two epochs because the leader schedule is also generated at slot 0 for the next epoch.&#x20;

The length of the first two epochs can be specified in the genesis config as well.&#x20;

The minimum length of the first epochs must be greater than or equal to the maximum rollback depth as defined in Tower BFT.

## Leader Schedule Generation Algorithm

Leader schedule is generated using a predefined seed.&#x20;

The process is as follows:

1. Periodically use the PoH tick height (a monotonically increasing counter) to seed a stable pseudo-random algorithm.
2. At that height, sample the bank for all the staked accounts with leader identities that have voted within a cluster-configured number of ticks. The sample is called the active set.
3. Sort the active set by stake weight.
4. Use the random seed to select nodes weighted by stake to create a stake-weighted ordering.
5. This ordering becomes valid after a cluster-configured number of ticks.

## Schedule Attack Vectors

## Seed

The seed that is selected is predictable but unbiasable.&#x20;

There is no grinding attack to influence its outcome.

## Active Set

A leader can bias the active set by censoring validator votes.&#x20;

Two possible ways exist for leaders to censor the active set:

* Ignore votes from validators
* Refuse to vote for blocks with votes from validators

To reduce the likelihood of censorship, the active set is calculated at the leader schedule offset boundary over an active set sampling duration.&#x20;

The active set sampling duration is long enough such that votes will have been collected by multiple leaders.

## Staking

Leaders can censor new staking transactions or refuse to validate blocks with new stakes.&#x20;

This attack is similar to censorship of validator votes.

## Validator operational key loss

Leaders and validators are expected to use ephemeral keys for operation, and stake owners authorize the validators to do work with their stake via delegation.

The cluster should be able to recover from the loss of all the ephemeral keys used by leaders and validators, which could occur through a common software vulnerability shared by all the nodes.&#x20;

Stake owners should be able to vote directly by co-signing a validator vote even though the stake is currently delegated to a validator.

## Appending Entries

The lifetime of a leader schedule is called an epoch. The epoch is split into slots, where each slot has a duration of T PoH ticks.

A leader transmits entries during its slot.&#x20;

After T ticks, all the validators switch to the next scheduled leader.&#x20;

Validators must ignore entries sent outside a leader's assigned slot.

All T ticks must be observed by the next leader for it to build its own entries on.&#x20;

If entries are not observed (leader is down) or entries are invalid (leader is buggy or malicious), the next leader must produce ticks to fill the previous leader's slot.

&#x20;Note that the next leader should do repair requests in parallel, and postpone sending ticks until it is confident other validators also failed to observe the previous leader's entries.

&#x20;If a leader incorrectly builds on its own ticks, the leader following it must replace all its ticks.


# Fork Generation

Fork Generation

This section describes how forks naturally occur as a consequence of leader rotation.

## Overview <a href="#overview" id="overview"></a>

Nodes take turns being leader and generating the PoH that encodes state changes.&#x20;

The cluster can tolerate loss of connection to any leader by synthesizing what the leader ***would*** have generated had it been connected but not ingesting any state changes.&#x20;

The possible number of forks is thereby limited to a "there/not-there" skip list of forks that may arise on leader rotation slot boundaries.&#x20;

At any given slot, only a single leader's transactions will be accepted.

## Message Flow <a href="#message-flow" id="message-flow"></a>

1. Transactions are ingested by the current leader.
2. Leader filters valid transactions.
3. Leader executes valid transactions updating its state.
4. Leader packages transactions into entries based off its current PoH slot.
5. Leader transmits the entries to validator nodes (in signed shreds)
   1. The PoH stream includes ticks; empty entries that indicate liveness of the leader and the passage of time on the cluster.
   2. A leader's stream begins with the tick entries necessary to complete PoH back to the leader's most recently observed prior leader slot.
6. Validators retransmit entries to peers in their set and to further downstream nodes.
7. Validators validate the transactions and execute them on their state.
8. Validators compute the hash of the state.
9. At specific times, i.e. specific PoH tick counts, validators transmit votes to the leader.
   1. Votes are signatures of the hash of the computed state at that PoH tick count.
   2. Votes are also propagated via gossip.
10. Leader executes the votes, the same as any other transaction, and broadcasts them to the cluster.
11. Validators observe their votes and all the votes from the cluster.

## Partitions, Forks <a href="#partitions-forks" id="partitions-forks"></a>

Forks can arise at PoH tick counts that correspond to a vote. The next leader may not have observed the last vote slot and may start their slot with generated virtual PoH entries.&#x20;

These empty ticks are generated by all nodes in the cluster at a cluster-configured rate for hashes/per/tick `Z`.

There are only two possible versions of the PoH during a voting slot: PoH with `T` ticks and entries generated by the current leader, or PoH with just ticks.&#x20;

The "just ticks" version of the PoH can be thought of as a virtual ledger, one that all nodes in the cluster can derive from the last tick in the previous slot.

Validators can ignore forks at other points (e.g. from the wrong leader), or slash the leader responsible for the fork.

Validators vote based on a greedy choice to maximize their reward described in Tower BFT.

### Validator's View <a href="#validators-view" id="validators-view"></a>

#### **Time Progression**

The diagram below represents a validator's view of the PoH stream with possible forks over time. L1, L2, etc. are leader slots, and `E`s represent entries from that leader during that leader's slot.&#x20;

The `x`s represent ticks only, and time flows downwards in the diagram.

<figure><img src="/files/AeYOsy0CE4Vzpk1CwOJI" alt=""><figcaption></figcaption></figure>

Note that an `E` appearing on 2 forks at the same slot is a slashable condition, so a validator observing `E3` and `E3'` can slash L3 and safely choose `x` for that slot.&#x20;

Once a validator commits to a fork, other forks can be discarded below that tick count. For any slot, validators need only consider a single "has entries" chain or a "ticks only" chain to be proposed by a leader.&#x20;

But multiple virtual entries may overlap as they link back to the a previous slot.

**Time Division**

It's useful to consider leader rotation over PoH tick count as time division of the job of encoding state for the cluster.&#x20;

The following table presents the above tree of forks as a time-divided ledger.

| leader slot      | L1 | L2 | L3 | L4 | L5 |
| ---------------- | -- | -- | -- | -- | -- |
| data             | E1 | E2 | E3 | E4 | E5 |
| ticks since prev |    |    |    | x  | xx |

Note that only data from leader L3 will be accepted during leader slot L3. Data from L3 may include "catchup" ticks back to a slot other than L2 if L3 did not observe L2's data. L4 and L5's transmissions include the "ticks to prev" PoH entries.

This arrangement of the network data streams permits nodes to save exactly this to the ledger for replay, restart, and checkpoints.

### Leader's View <a href="#leaders-view" id="leaders-view"></a>

When a new leader begins a slot, it must first transmit any PoH (ticks) required to link the new slot with the most recently observed and voted slot.&#x20;

The fork the leader proposes would link the current slot to a previous fork that the leader has voted on with virtual ticks.


# Managing Forks

The ledger is permitted to fork at slot boundaries. The resulting data structure forms a tree called a *blockstore*.&#x20;

When the validator interprets the blockstore, it must maintain state for each fork in the chain. We call each instance an *active fork*.&#x20;

It is the responsibility of a validator to weigh those forks, such that it may eventually select a fork.

A validator selects a fork by submiting a vote to a slot leader on that fork.&#x20;

The vote commits the validator for a duration of time called a *lockout period*. The validator is not permitted to vote on a different fork until that lockout period expires.

&#x20;Each subsequent vote on the same fork doubles the length of the lockout period.&#x20;

After some cluster-configured number of votes (currently 32), the length of the lockout period reaches what's called *max lockout*.&#x20;

Until the max lockout is reached, the validator has the option to wait until the lockout period is over and then vote on another fork.&#x20;

When it votes on another fork, it performs an operation called *rollback*, whereby the state rolls back in time to a shared checkpoint and then jumps forward to the tip of the fork that it just voted on.&#x20;

The maximum distance that a fork may roll back is called the *rollback depth*. Rollback depth is the number of votes required to achieve max lockout.&#x20;

Whenever a validator votes, any checkpoints beyond the rollback depth become unreachable.&#x20;

That is, there is no scenario in which the validator will need to roll back beyond rollback depth.&#x20;

It therefore may safely *prune* unreachable forks and *squash* all checkpoints beyond rollback depth into the root checkpoint.

## Active Forks <a href="#active-forks" id="active-forks"></a>

An active fork is as a sequence of checkpoints that has a length at least one longer than the rollback depth.&#x20;

The shortest fork will have a length exactly one longer than the rollback depth. For example:

<figure><img src="/files/pxnBlkbp2p0FzPDtMH8e" alt=""><figcaption></figcaption></figure>

The following sequences are *active forks*:

* {4, 2, 1}
* {5, 2, 1}
* {6, 3, 1}
* {7, 3, 1}

## Pruning and Squashing <a href="#pruning-and-squashing" id="pruning-and-squashing"></a>

A validator may vote on any checkpoint in the tree. In the diagram above, that's every node except the leaves of the tree.&#x20;

After voting, the validator prunes nodes that fork from a distance farther than the rollback depth and then takes the opportunity to minimize its memory usage by squashing any nodes it can into the root.

Starting from the example above, with a rollback depth of 2, consider a vote on 5 versus a vote on 6. First, a vote on 5:

<figure><img src="/files/vPtrVkE2JdwaD4gAghyF" alt=""><figcaption></figcaption></figure>

The new root is 2, and any active forks that are not descendants from 2 are pruned.

Alternatively, a vote on 6:

<figure><img src="/files/TcGy7arvkDK9o2P7jSWJ" alt=""><figcaption></figcaption></figure>

The tree remains with a root of 1, since the active fork starting at 6 is only 2 checkpoints from the root.


# Turbine Block Propagation

## Turbine Block Propagation

A PUT cluster uses a multi-layer block propagation mechanism called Turbine to broadcast transaction shreds to all nodes with minimal amount of duplicate messages.&#x20;

The cluster divides itself into small collections of nodes, called neighborhoods.&#x20;

Each node is responsible for sharing any data it receives with the other nodes in its neighborhood, as well as propagating the data on to a small set of nodes in other neighborhoods.&#x20;

This way each node only has to communicate with a small number of nodes.

During its slot, the leader node distributes shreds between the validator nodes in the first neighborhood (layer 0).&#x20;

Each validator shares its data within its neighborhood, but also retransmits the shreds to one node in some neighborhoods in the next layer (layer 1).&#x20;

The layer-1 nodes each share their data with their neighborhood peers, and retransmit to nodes in the next layer, etc, until all nodes in the cluster have received all the shreds.&#x20;

## Neighborhood Assignment - Weighted Selection\#

In order for data plane fanout to work, the entire cluster must agree on how the cluster is divided into neighborhoods.&#x20;

To achieve this, all the recognized validator nodes (the TVU peers) are sorted by stake and stored in a list.&#x20;

This list is then indexed in different ways to figure out neighborhood boundaries and retransmit peers. For example, the leader will simply select the first nodes to make up layer 0.&#x20;

These will automatically be the highest stake holders, allowing the heaviest votes to come back to the leader first. Layer 0 and lower-layer nodes use the same logic to find their neighbors and next layer peers.

To reduce the possibility of attack vectors, each shred is transmitted over a random tree of neighborhoods.&#x20;

Each node uses the same set of nodes representing the cluster.&#x20;

A random tree is generated from the set for each shred using a seed derived from the leader id, slot and shred index.&#x20;

## Layer and Neighborhood Structure

The current leader makes its initial broadcasts to at most DATA\_PLANE\_FANOUT nodes.&#x20;

If this layer 0 is smaller than the number of nodes in the cluster, then the data plane fanout mechanism adds layers below.&#x20;

Subsequent layers follow these constraints to determine layer-capacity: Each neighborhood contains DATA\_PLANE\_FANOUT nodes. Layer 0 starts with 1 neighborhood with fanout nodes.&#x20;

The number of nodes in each additional layer grows by a factor of fanout.

As mentioned above, each node in a layer only has to broadcast its shreds to its neighbors and to exactly 1 node in some next-layer neighborhoods, instead of to every TVU peer in the cluster.&#x20;

A good way to think about this is, layer 0 starts with 1 neighborhood with fanout nodes, layer 1 adds fanout neighborhoods, each with fanout nodes and layer 2 will have fanout \* number of nodes in layer 1 and so on.

This way each node only has to communicate with a maximum of 2 \* DATA\_PLANE\_FANOUT - 1 nodes.

The following diagram shows how the Leader sends shreds with a fanout of 2 to Neighborhood 0 in Layer 0 and how the nodes in Neighborhood 0 share their data with each other.

Leader sends shreds to Neighborhood 0 in Layer 0

The following diagram shows how Neighborhood 0 fans out to Neighborhoods 1 and 2.

<figure><img src="/files/WjF6SFVV74WFSzf0hpOT" alt=""><figcaption></figcaption></figure>

Neighborhood 0 Fanout to Neighborhood 1 and 2

<figure><img src="/files/wHDGLxpok4PB9KqCTVZU" alt=""><figcaption></figcaption></figure>

Finally, the following diagram shows a two layer cluster with a fanout of 2.

<figure><img src="/files/3o57Oz6HfHkXc0K8Sdg5" alt=""><figcaption></figcaption></figure>

Two layer cluster with a Fanout of 2&#x20;

### Configuration Values\#

DATA\_PLANE\_FANOUT - Determines the size of layer 0. Subsequent layers grow by a factor of DATA\_PLANE\_FANOUT.&#x20;

The number of nodes in a neighborhood is equal to the fanout value. Neighborhoods will fill to capacity before new ones are added, i.e if a neighborhood isn't full, it must be the last one.

Currently, configuration is set when the cluster is launched. In the future, these parameters may be hosted on-chain, allowing modification on the fly as the cluster sizes change.&#x20;

## Calculating the required FEC rate\#

Turbine relies on retransmission of packets between validators.&#x20;

Due to retransmission, any network wide packet loss is compounded, and the probability of the packet failing to reach its destination increases on each hop.&#x20;

The FEC rate needs to take into account the network wide packet loss, and the propagation depth.

A shred group is the set of data and coding packets that can be used to reconstruct each other.&#x20;

Each shred group has a chance of failure, based on the likelyhood of the number of packets failing that exceeds the FEC rate.&#x20;

If a validator fails to reconstruct the shred group, then the block cannot be reconstructed, and the validator has to rely on repair to fixup the blocks.

The probability of the shred group failing can be computed using the binomial distribution.

&#x20;If the FEC rate is 16:4, then the group size is 20, and at least 4 of the shreds must fail for the group to fail.&#x20;

Which is equal to the sum of the probability of 4 or more trails failing out of 20.

Probability of a block succeeding in turbine:

* Probability of packet failure: P = 1 - (1 - network\_packet\_loss\_rate)^2
* FEC rate: K:M
* Number of trials: N = K + M
* Shred group failure rate: S = SUM of i=0 -> M for binomial(prob\_failure = P, trials = N, failures = i)
* Shreds per block: G
* Block success rate: B = (1 - S) ^ (G / N)
* Binomial distribution for exactly i results with probability of P in N trials is defined as (N choose i) \* P^i \* (1 - P)^(N-i)

For example:

* Network packet loss rate is 15%.
* 50k tps network generates 6400 shreds per second.
* FEC rate increases the total shreds per block by the FEC ratio.

With a FEC rate: 16:4

* G = 8000
* P = 1 - 0.85 \* 0.85 = 1 - 0.7225 = 0.2775
* S = SUM of i=0 -> 4 for binomial(prob\_failure = 0.2775, trials = 20, failures = i) = 0.689414
* B = (1 - 0.689) ^ (8000 / 20) = 10^-203

With FEC rate of 16:16

* G = 12800
* S = SUM of i=0 -> 32 for binomial(prob\_failure = 0.2775, trials = 64, failures = i) = 0.002132
* B = (1 - 0.002132) ^ (12800 / 32) = 0.42583

With FEC rate of 32:32

* G = 12800
* S = SUM of i=0 -> 32 for binomial(prob\_failure = 0.2775, trials = 64, failures = i) = 0.000048
* B = (1 - 0.000048) ^ (12800 / 64) = 0.99045

## Neighborhoods

The following diagram shows how two neighborhoods in different layers interact. To cripple a neighborhood, enough nodes (erasure codes +1) from the neighborhood above need to fail.&#x20;

Since each neighborhood receives shreds from multiple nodes in a neighborhood in the upper layer, we'd need a big network failure in the upper layers to end up with incomplete data.

Inner workings of a neighborhood

<figure><img src="/files/Vk2wCWTLLagUuTY1qJ5A" alt=""><figcaption></figcaption></figure>


# Commitment Status

Commitment Status

Commitment Status

The commitment metric gives clients a standard measure of the network confirmation for the block. Clients can then use this information to derive their own measures of commitment.There are three specific commitment statuses:

* Processed
* Confirmed
* Finalized

| Property                              | Processed | Confirmed | Finalized |
| ------------------------------------- | --------- | --------- | --------- |
| Received block                        | X         | X         | X         |
| Block on majority fork                | X         | X         | X         |
| Block contains target tx              | X         | X         | X         |
| 66%+ stake voted on block             | -         | X         | X         |
| 31+ confirmed blocks built atop block | -         | -         | X         |


# Secure Vote Signing

Secure Vote Signing

A validator receives entries from the current leader and submits votes confirming those entries are valid.&#x20;

This vote submission presents a security challenge, because forged votes that violate consensus rules could be used to slash the validator's stake.

The validator votes on its chosen fork by submitting a transaction that uses an asymmetric key to sign the result of its validation work.&#x20;

Other entities can verify this signature using the validator's public key.&#x20;

If the validator's key is used to sign incorrect data (e.g. votes on multiple forks of the ledger), the node's stake or its resources could be compromised.

## Validators, Vote Signers, and Stakeholders <a href="#validators-vote-signers-and-stakeholders" id="validators-vote-signers-and-stakeholders"></a>

When a validator receives multiple blocks for the same slot, it tracks all possible forks until it can determine a "best" one. A validator selects the best fork by submitting a vote to it.

A stakeholder is an identity that has control of the staked capital. The stakeholder can delegate its stake to the vote signer.&#x20;

Once a stake is delegated, the vote signer's votes represent the voting weight of all the delegated stakes, and produce rewards for all the delegated stakes.

## Validator voting <a href="#validator-voting" id="validator-voting"></a>

A validator node, at startup, creates a new vote account and registers it with the cluster via gossip.&#x20;

The other nodes on the cluster include the new validator in the active set.&#x20;

Subsequently, the validator submits a "new vote" transaction signed with the validator's voting private key on each voting event.


# Stake Delegation and Rewards

## Stake Delegation and Rewards <a href="#stake-delegation-and-rewards" id="stake-delegation-and-rewards"></a>

Stakers are rewarded for helping to validate the ledger.&#x20;

They do this by delegating their stake to validator nodes. Those validators do the legwork of replaying the ledger and sending votes to a per-node vote account to which stakers can delegate their stakes.&#x20;

The rest of the cluster uses those stake-weighted votes to select a block when forks arise. Both the validator and staker need some economic incentive to play their part.&#x20;

The validator needs to be compensated for its hardware and the staker needs to be compensated for the risk of getting its stake slashed.&#x20;

The economics are covered instaking rewards. This section, on the other hand, describes the underlying mechanics of its implementation.

## Basic Design

The general idea is that the validator owns a Vote account.&#x20;

The Vote account tracks validator votes, counts validator generated credits, and provides any additional validator specific state.&#x20;

The Vote account is not aware of any stakes delegated to it and has no staking weight.A separate Stake account (created by a staker) names a Vote account to which the stake is delegated.&#x20;

Rewards generated are proportional to the amount of lamports staked. The Stake account is owned by the staker only.&#x20;

Some portion of the lamports stored in this account are the stake.

## Passive Delegation

Any number of Stake accounts can delegate to a single Vote account without an interactive action from the identity controlling the Vote account or submitting votes to the account.

The total stake allocated to a Vote account can be calculated by the sum of all the Stake accounts that have the Vote account pubkey as the StakeState::Stake::voter\_pubkey.

## Vote and Stake accounts

​The rewards process is split into two on-chain programs.&#x20;

The Vote program solves the problem of making stakes slashable.&#x20;

The Stake program acts as custodian of the rewards pool and provides for passive delegation.&#x20;

The Stake program is responsible for paying rewards to staker and voter when shown that a staker's delegate has participated in validating the ledger.

### VoteState#​

VoteState is the current state of all the votes the validator has submitted to the network.&#x20;

VoteState contains the following state information:

* votes - The submitted votes data structure.
* credits - The total number of rewards this Vote program has generated over its lifetime.
* root\_slot - The last slot to reach the full lockout commitment necessary for rewards.
* commission - The commission taken by this VoteState for any rewards claimed by staker's Stake accounts. This is the percentage ceiling of the reward.
* Account::lamports - The accumulated lamports from the commission. These do not count as stakes.
* authorized\_voter - Only this identity is authorized to submit votes. This field can only modified by this identity.
* node\_pubkey - The Solana node that votes in this account.
* authorized\_withdrawer - the identity of the entity in charge of the lamports of this account, separate from the account's address and the authorized vote signer.

### VoteInstruction::Initialize(VoteInit)#​

&#x20; account\[0] - RW - The VoteState.

&#x20; VoteInit carries the new vote account's node\_pubkey, authorized\_voter, authorized\_withdrawer, and commission.other VoteState members defaulted.

### VoteInstruction::Authorize(Pubkey, VoteAuthorize)

Updates the account with a new authorized voter or withdrawer, according to the VoteAuthorize parameter (Voter or Withdrawer).&#x20;

The transaction must be signed by the Vote account's current authorized\_voter or authorized\_withdrawer.

* account\[0] - RW - The VoteState.&#x20;

&#x20;    VoteState::authorized\_voter or authorized\_withdrawer is set to Pubkey.

### VoteInstruction::AuthorizeWithSeed(VoteAuthorizeWithSeedArgs)

Updates the account with a new authorized voter or withdrawer, according to the VoteAuthorize parameter (Voter or Withdrawer).&#x20;

Unlike VoteInstruction::Authorize this instruction is for use when the Vote account's current authorized\_voter or authorized\_withdrawer is a derived key.&#x20;

The transaction must be signed by someone who can sign for the base key of that derived key.

* account\[0] - RW - The VoteState. VoteState::authorized\_voter or authorized\_withdrawer is set to Pubkey.

### VoteInstruction::Vote(Vote)

* account\[0] - RW - The VoteState. VoteState::lockouts and VoteState::credits are updated according to voting lockout rules seeTower BFT.
* account\[1] - RO - sysvar::slot\_hashes A list of some N most recent slots and their hashes for the vote to be verified against.
* account\[2] - RO - sysvar::clock The current network time, expressed in slots, epochs.

### StakeState

A StakeState takes one of four forms, StakeState::Uninitialized, StakeState::Initialized, StakeState::Stake, and StakeState::RewardsPool.&#x20;

Only the first three forms are used in staking, but only StakeState::Stake is interesting.&#x20;

All RewardsPools are created at genesis.

### StakeState::Stake

StakeState::Stake is the current delegation preference of the staker and contains the following state information:

* Account::lamports - The lamports available for staking.
* stake - the staked amount (subject to warmup and cooldown) for generating rewards, always less than or equal to Account::lamports.
* voter\_pubkey - The pubkey of the VoteState instance the lamports are delegated to.
* credits\_observed - The total credits claimed over the lifetime of the program.
* activated - the epoch at which this stake was activated/delegated. The full stake will be counted after warmup.
* deactivated - the epoch at which this stake was de-activated, some cooldown epochs are required before the account is fully deactivated, and the stake available for withdrawal.
* authorized\_staker - the pubkey of the entity that must sign delegation, activation, and deactivation transactions.
* authorized\_withdrawer - the identity of the entity in charge of the lamports of this account, separate from the account's address, and the authorized staker.

### StakeState::RewardsPool​

To avoid a single network-wide lock or contention in redemption, 256 RewardsPools are part of genesis under pre-determined keys, each with std::u64::MAX credits to be able to satisfy redemptions according to point value.

The Stakes and the RewardsPool are accounts that are owned by the same Stake program.

### StakeInstruction::DelegateStake

The Stake account is moved from Initialized to StakeState::Stake form, or from a deactivated (i.e. fully cooled-down) StakeState::Stake to activated StakeState::Stake.&#x20;

This is how stakers choose the vote account and validator node to which their stake account lamports are delegated.&#x20;

The transaction must be signed by the stake's authorized\_staker.

* account\[0] - RW - The StakeState::Stake instance. StakeState::Stake::credits\_observed is initialized to VoteState::credits, StakeState::Stake::voter\_pubkey is initialized to account\[1].&#x20;

&#x20;    If this is the initial delegation of stake, StakeState::Stake::stake is initialized to the account's     balance in lamports, StakeState::Stake::activated is initialized to the current Bank epoch, and StakeState::Stake::deactivated is initialized to std::u64::MAX

* account\[1] - R - The VoteState instance.
* account\[2] - R - sysvar::clock account, carries information about current Bank epoch.
* account\[3] - R - sysvar::stakehistory account, carries information about stake history.
* account\[4] - R - stake::Config account, carries warmup, cooldown, and slashing configuration.

### StakeInstruction::Authorize(Pubkey, StakeAuthorize)

Updates the account with a new authorized staker or withdrawer, according to the StakeAuthorize parameter (Staker or Withdrawer).&#x20;

The transaction must be by signed by the Stakee account's current authorized\_staker or authorized\_withdrawer.&#x20;

Any stake lock-up must have expired, or the lock-up custodian must also sign the transaction.

* account\[0] - RW - The StakeState.

&#x20;   StakeState::authorized\_staker or authorized\_withdrawer is set to to Pubkey.

### StakeInstruction::Deactivate

​A staker may wish to withdraw from the network.&#x20;

To do so he must first deactivate his stake, and wait for cooldown.&#x20;

The transaction must be signed by the stake's authorized\_staker.

* account\[0] - RW - The StakeState::Stake instance that is deactivating.
* account\[1] - R - sysvar::clock account from the Bank that carries current epoch.

StakeState::Stake::deactivated is set to the current epoch + cooldown.&#x20;

The account's stake will ramp down to zero by that epoch, and Account::lamports will be available for withdrawal.

### StakeInstruction::Withdraw(u64)

​Lamports build up over time in a Stake account and any excess over activated stake can be withdrawn.&#x20;

The transaction must be signed by the stake's authorized\_withdrawer.

* account\[0] - RW - The StakeState::Stake from which to withdraw.
* account\[1] - RW - Account that should be credited with the withdrawn lamports.
* account\[2] - R - sysvar::clock account from the Bank that carries current epoch, to calculate stake.
* account\[3] - R - sysvar::stake\_history account from the Bank that carries stake warmup/cooldown history.

## Benefits of the design

* Single vote for all the stakers.
* Clearing of the credit variable is not necessary for claiming rewards.
* Each delegated stake can claim its rewards independently.
* Commission for the work is deposited when a reward is claimed by the delegated stake.

## Example Callflow

<figure><img src="/files/Dtpxg4xK8VA82Mo62YIW" alt=""><figcaption></figcaption></figure>

​​Passive Staking Callflow

## Staking Rewards#​

The specific mechanics and rules of the validator rewards regime is outlined here.

&#x20;Rewards are earned by delegating stake to a validator that is voting correctly.&#x20;

Voting incorrectly exposes that validator's stakes toslashing.

### Basics​

The network pays rewards from a portion of networkinflation.&#x20;

The number of lamports available to pay rewards for an epoch is fixed and must be evenly divided among all staked nodes according to their relative stake weight and participation.&#x20;

The weighting unit is called apoint.

Rewards for an epoch are not available until the end of that epoch.

At the end of each epoch, the total number of points earned during the epoch is summed and used to divide the rewards portion of epoch inflation to arrive at a point value.&#x20;

This value is recorded in the bank in asysvarthat maps epochs to point values.

During redemption, the stake program counts the points earned by the stake for each epoch, multiplies that by the epoch's point value, and transfers lamports in that amount from a rewards account into the stake and vote accounts according to the vote account's commission setting.

### Economics

Point value for an epoch depends on aggregate network participation.&#x20;

If participation in an epoch drops off, point values are higher for those that do participate.

### Earning credits\#

Validators earn one vote credit for every correct vote that exceeds maximum lockout, i.e. every time the validator's vote account retires a slot from its lockout list, making that vote a root for the node.

Stakers who have delegated to that validator earn points in proportion to their stake. Points earned is the product of vote credits and stake.

### Stake warmup, cooldown, withdrawal

Stakes, once delegated, do not become effective immediately. They must first pass through a warmup period.&#x20;

During this period some portion of the stake is considered "effective", the rest is considered "activating".&#x20;

Changes occur on epoch boundaries.

The stake program limits the rate of change to total network stake, reflected in the stake program's `config::warmup_rate` (set to 25% per epoch in the current implementation).

The amount of stake that can be warmed up each epoch is a function of the previous epoch's total effective stake, total activating stake, and the stake program's configured warmup rate.

Cooldown works the same way. Once a stake is deactivated, some part of it is considered "effective", and also "deactivating".&#x20;

As the stake cools down, it continues to earn rewards and be exposed to slashing, but it also becomes available for withdrawal.

Bootstrap stakes are not subject to warmup.

Rewards are paid against the "effective" portion of the stake for that epoch.

### **Warmup example**

Consider the situation of a single stake of 1,000 activated at epoch N, with network warmup rate of 20%, and a quiescent total network stake at epoch N of 2,000.

At epoch N+1, the amount available to be activated for the network is 400 (20% of 2000), and at epoch N, this example stake is the only stake activating, and so is entitled to all of the warmup room available.

| epoch | effective | activating | total effective | total activating |
| ----- | --------- | ---------- | --------------- | ---------------- |
| N-1   | ​         | ​          | 2,000           | 0                |
| N     | 0         | 1,000      | 2,000           | 1,000            |
| N+1   | 400       | 600        | 2,400           | 600              |
| N+2   | 880       | 120        | 2,880           | 120              |
| N+3   | 1000      | 0          | 3,000           | 0                |

Were 2 stakes (X and Y) to activate at epoch N, they would be awarded a portion of the 20% in proportion to their stakes.&#x20;

At each epoch effective and activating for each stake is a function of the previous epoch's state.

| epoch | X eff | X act | Y eff | Y act | total effective | total activating |
| ----- | ----- | ----- | ----- | ----- | --------------- | ---------------- |
| N-1   | ​     | ​     | ​     | ​     | 2,000           | 0                |
| N     | 0     | 1,000 | 0     | 200   | 2,000           | 1,200            |
| N+1   | 333   | 667   | 67    | 133   | 2,400           | 800              |
| N+2   | 733   | 267   | 146   | 54    | 2,880           | 321              |
| N+3   | 1000  | 0     | 200   | 0     | 3,200           | 0                |

### **Withdrawal**

Only lamports in excess of effective+activating stake may be withdrawn at any time.&#x20;

This means that during warmup, effectively no stake can be withdrawn.&#x20;

During cooldown, any tokens in excess of effective stake may be withdrawn (activating == 0).&#x20;

Because earned rewards are automatically added to stake, withdrawal is generally only possible after deactivation.

### **Lock-up**

Stake accounts support the notion of lock-up, wherein the stake account balance is unavailable for withdrawal until a specified time.&#x20;

Lock-up is specified as an epoch height, i.e. the minimum epoch height that must be reached by the network before the stake account balance is available for withdrawal, unless the transaction is also signed by a specified custodian.&#x20;

This information is gathered when the stake account is created, and stored in the Lockup field of the stake account's state.&#x20;

Changing the authorized staker or withdrawer is also subject to lock-up, as such an operation is effectively a transfer.


# Validators


# Overview

Anatomy of a Validator

<figure><img src="/files/014moqCtYkWI5iyfJ2cc" alt=""><figcaption></figcaption></figure>

## Pipelining <a href="#pipelining" id="pipelining"></a>

The validators make extensive use of an optimization common in CPU design, called *pipelining*.&#x20;

Pipelining is the right tool for the job when there's a stream of input data that needs to be processed by a sequence of steps, and there's different hardware responsible for each.&#x20;

The quintessential example is using a washer and dryer to wash/dry/fold several loads of laundry. Washing must occur before drying and drying before folding, but each of the three operations is performed by a separate unit.&#x20;

To maximize efficiency, one creates a pipeline of *stages*.&#x20;

We'll call the washer one stage, the dryer another, and the folding process a third. To run the pipeline, one adds a second load of laundry to the washer just after the first load is added to the dryer.&#x20;

Likewise, the third load is added to the washer after the second is in the dryer and the first is being folded. In this way, one can make progress on three loads of laundry simultaneously.&#x20;

Given infinite loads, the pipeline will consistently complete a load at the rate of the slowest stage in the pipeline.

## Pipelining in the Validator <a href="#pipelining-in-the-validator" id="pipelining-in-the-validator"></a>

The validator contains two pipelined processes, one used in leader mode called the TPU and one used in validator mode called the TVU.&#x20;

In both cases, the hardware being pipelined is the same, the network input, the GPU cards, the CPU cores, writes to disk, and the network output.&#x20;

What it does with that hardware is different.&#x20;

The TPU exists to create ledger entries whereas the TVU exists to validate them.


# TPU

##

TPU (Transaction Processing Unit) is the logic of the validator responsible for block production.

<figure><img src="/files/Y2KwkrTsFuXG5THGmc9W" alt=""><figcaption></figcaption></figure>

Transactions encoded and sent in UDP packets flow into the validator from clients (other validators/users of the network) as follows:

* fetch stage: allocates packet memory and reads the packet data from the network socket and applies some coalescing of packets received at the same time.
* sigverify stage: deduplicates packets and applies some load-shedding to remove excessive packets before then filtering packets with invalid signatures by setting the packet's discard flag.
* banking stage: decides whether to forward, hold or process packets received. Once it detects the node is the block producer it processes held packets and newly received packets with a Bank at the tip slot.
* broadcast stage: receives the valid transactions formed into Entry's from banking stage and packages them into shreds to send to network peers through the turbine tree structure. Serializes, signs, and generates erasure codes before sending the packets to the appropriate network peer.


# TVU

## TVU&#x20;

<figure><img src="/files/u5DHUuK0qvMAKWoXXjiq" alt=""><figcaption></figcaption></figure>

## Retransmit Stage <a href="#retransmit-stage" id="retransmit-stage"></a>

<figure><img src="/files/kkDk1SEiIJQswz9HYbd8" alt=""><figcaption></figcaption></figure>


# Blockstore

## Blockstore <a href="#blockstore" id="blockstore"></a>

After a block reaches finality, all blocks from that one on down to the genesis block form a linear chain with the familiar name blockchain.&#x20;

Until that point, however, the validator must maintain all potentially valid chains, called forks.&#x20;

The process by which forks naturally form as a result of leader rotation is described infork generation.&#x20;

The blockstore data structure described here is how a validator copes with those forks until blocks are finalized.

The blockstore allows a validator to record every shred it observes on the network, in any order, as long as the shred is signed by the expected leader for a given slot.Shreds are moved to a fork-able key space the tuple of leader slot + shred index (within the slot).&#x20;

This permits the skip-list structure of the Solana protocol to be stored in its entirety, without a-priori choosing which fork to follow, which Entries to persist or when to persist them.

Repair requests for recent shreds are served out of RAM or recent files and out of deeper storage for less recent shreds, as implemented by the store backing Blockstore.

## Functionalities of Blockstore

1. Persistence: the Blockstore lives in the front of the nodes verificationpipeline, right behind network receive and signature verification. If theshred received is consistent with the leader schedule (i.e. was signed by theleader for the indicated slot), it is immediately stored.
2. Repair: repair is the same as window repair above, but able to serve anyshred that's been received. Blockstore stores shreds with signatures,preserving the chain of origination.
3. Forks: Blockstore supports random access of shreds, so can support avalidator's need to rollback and replay from a Bank checkpoint.
4. Restart: with proper pruning/culling, the Blockstore can be replayed byordered enumeration of entries from slot 0. The logic of the replay stage(i.e. dealing with forks) will have to be used for the most recent entries inthe Blockstore.

## Blockstore Design​ <a href="#blockstore-design" id="blockstore-design"></a>

1. Entries in the Blockstore are stored as key-value pairs, where the key is the concatenated slot index and shred index for an entry, and the value is the entry data. Note shred indexes are zero-based for each slot (i.e. they're slot-relative).
2. The Blockstore maintains metadata for each slot, in the `SlotMeta` struct containing:
   * `slot_index` - The index of this slot
   * `num_blocks` - The number of blocks in the slot (used for chaining to a previous slot)
   * `consumed` - The highest shred index `n`, such that for all `m < n`, there exists a shred in this slot with shred index equal to `n` (i.e. the highest consecutive shred index).
   * `received` - The highest received shred index for the slot
   * `next_slots` - A list of future slots this slot could chain to. Used when rebuildingthe ledger to find possible fork points.
   * `last_index` - The index of the shred that is flagged as the last shred for this slot. This flag on a shred will be set by the leader for a slot when they are transmitting the last shred for a slot.
   * `is_connected` - True iff every block from 0...slot forms a full sequence without any holes. We can derive is\_connected for each slot with the following rules. Let slot(n) be the slot with index `n`, and slot(n).is\_full() is true if the slot with index `n` has all the ticks expected for that slot. Let is\_connected(n) be the statement that "the slot(n).is\_connected is true". Then:is\_connected(0) is\_connected(n+1) iff (is\_connected(n) and slot(n).is\_full()
3. Chaining - When a shred for a new slot `x` arrives, we check the number of blocks (`num_blocks`) for that new slot (this information is encoded in the shred). We then know that this new slot chains to slot `x - num_blocks`.
4. Subscriptions - The Blockstore records a set of slots that have been "subscribed" to. This means entries that chain to these slots will be sent on the Blockstore channel for consumption by the ReplayStage. See the `Blockstore APIs` for details.
5. Update notifications - The Blockstore notifies listeners when slot(n).is\_connected is flipped from false to true for any `n`.

## Blockstore APIs <a href="#blockstore-apis" id="blockstore-apis"></a>

The Blockstore offers a subscription based API that ReplayStage uses to ask for entries it's interested in.&#x20;

The entries will be sent on a channel exposed by the Blockstore.&#x20;

These subscription API's are as follows: 1. `fn get_slots_since(slot_indexes: &[u64]) -> Vec<SlotMeta>`: Returns new slots connecting to any element of the list `slot_indexes`.

1. `fn get_slot_entries(slot_index: u64, entry_start_index: usize, max_entries: Option<u64>) -> Vec<Entry>`: Returns the entry vector for the slot starting with `entry_start_index`, capping the result at `max` if `max_entries == Some(max)`, otherwise, no upper limit on the length of the return vector is imposed.

Note: Cumulatively, this means that the replay stage will now have to know when a slot is finished, and subscribe to the next slot it's interested in to get the next set of entries.&#x20;

Previously, the burden of chaining slots fell on the Blockstore.

## Interfacing with Bank <a href="#interfacing-with-bank" id="interfacing-with-bank"></a>

The bank exposes to replay stage:

1. `prev_hash`: which PoH chain it's working on as indicated by the hash of the lastentry it processed
2. `tick_height`: the ticks in the PoH chain currently being verified by thisbank
3. `votes`: a stack of records that contain: 1. `prev_hashes`: what anything after this vote must chain to in PoH 2. `tick_height`: the tick height at which this vote was cast 3. `lockout period`: how long a chain must be observed to be in the ledger tobe able to be chained below this vote

Replay stage uses Blockstore APIs to find the longest chain of entries it can hang off a previous vote.&#x20;

If that chain of entries does not hang off the latest vote, the replay stage rolls back the bank to that vote and replays the chain from there.

## Pruning Blockstore <a href="#pruning-blockstore" id="pruning-blockstore"></a>

Once Blockstore entries are old enough, representing all the possible forks becomes less useful, perhaps even problematic for replay upon restart.&#x20;

Once a validator's votes have reached max lockout, however, any Blockstore contents that are not on the PoH chain for that vote for can be pruned, expunged.


# Gossip Service

## ​Gossip Service

The Gossip Service acts as a gateway to nodes in thecontrol plane.&#x20;

Validators use the service to ensure information is available to all other nodes in a cluster.&#x20;

The service broadcasts information using agossip protocol.

## Gossip Overview​

Nodes continuously share signed data objects among themselves in order to manage a cluster.&#x20;

For example, they share their contact information, ledger height, and votes.

Every tenth of a second, each node sends a "push" message and/or a "pull" message.&#x20;

Push and pull messages may elicit responses, and push messages may be forwarded on to others in the cluster.

Gossip runs on a well-known UDP/IP port or a port in a well-known range.&#x20;

Once a cluster is bootstrapped, nodes advertise to each other where to find their gossip endpoint (a socket address).

## Gossip Records

Records shared over gossip are arbitrary, but signed and versioned (with a timestamp) as needed to make sense to the node receiving them.&#x20;

If a node receives two records from the same source, it updates its own copy with the record with the most recent timestamp.

## Gossip Service Interface

### Push Message​

A node sends a push message to tells the cluster it has information to share.&#x20;

Nodes send push messages to PUSH\_FANOUT push peers.

Upon receiving a push message, a node examines the message for:

1. Duplication: if the message has been seen before, the node drops the message and may respond with `PushMessagePrune` if forwarded from a low staked node
2. New data: if the message is new to the node
   * Stores the new information with an updated version in its cluster info and purges any previous older value
   * Stores the message in `pushed_once` (used for detecting duplicates, purged after `PUSH_MSG_TIMEOUT * 5` ms)
   * Retransmits the messages to its own push peers
3. Expiration: nodes drop push messages that are older than `PUSH_MSG_TIMEOUT`

&#x20; &#x20;

### Push Peers, Prune Message\#

A nodes selects its push peers at random from the active set of known peers.&#x20;

The node keeps this selection for a relatively long time.&#x20;

When a prune message is received, the node drops the push peer that sent the prune.&#x20;

Prune is an indication that there is another, higher stake weighted path to that node than direct push.

The set of push peers is kept fresh by rotating a new node into the set every `PUSH_MSG_TIMEOUT/2` milliseconds.

### **Pull Message**

A node sends a pull message to ask the cluster if there is any new information.&#x20;

A pull message is sent to a single peer at random and comprises a Bloom filter that represents things it already has.&#x20;

A node receiving a pull message iterates over its values and constructs a pull response of things that miss the filter and would fit in a message.

A node constructs the pull Bloom filter by iterating over current values and recently purged values.

A node handles items in a pull response the same way it handles new data in a push message.

## Purging <a href="#purging" id="purging"></a>

Nodes retain prior versions of values (those updated by a pull or push) and expired values (those older than `GOSSIP_PULL_CRDS_TIMEOUT_MS`) in `purged_values` (things I recently had). Nodes purge `purged_values` that are older than `5 * GOSSIP_PULL_CRDS_TIMEOUT_MS`.

## Eclipse Attacks <a href="#eclipse-attacks" id="eclipse-attacks"></a>

An eclipse attack is an attempt to take over the set of node connections with adversarial endpoints.

This is relevant to our implementation in the following ways.

* Pull messages select a random node from the network. An eclipse attack on *pull* would require an attacker to influence the random selection in such a way that only adversarial nodes are selected for pull.
* Push messages maintain an active set of nodes and select a random fanout for every push message. An eclipse attack on *push* would influence the active set selection, or the random fanout selection.

### **Time and Stake based weights**

Weights are calculated based on `time since last picked` and the `natural log` of the `stake weight`.

Taking the `ln` of the stake weight allows giving all nodes a fairer chance of network coverage in a reasonable amount of time.

&#x20;It helps normalize the large possible `stake weight` differences between nodes.&#x20;

This way a node with low `stake weight`, compared to a node with large `stake weight` will only have to wait a few multiples of ln(`stake`) seconds before it gets picked.

There is no way for an adversary to influence these parameters.

### **Pull Message**

A node is selected as a pull target based on the weights described above.

### **Push Message**

A prune message can only remove an adversary from a potential connection.Just like *pull message*, nodes are selected into the active set based on weights.

## Notable differences from PlumTree <a href="#notable-differences-from-plumtree" id="notable-differences-from-plumtree"></a>

The active push protocol described here is based on Plum Tree. The main differences are:

* Push messages have a wallclock that is signed by the originator. Once the wallclock expires the message is dropped. A hop limit is difficult to implement in an adversarial setting.
* Lazy Push is not implemented because its not obvious how to prevent an adversary from forging the message fingerprint. A naive approach would allow an adversary to be prioritized for pull based on their input.


# The Runtime

## The Runtime

The runtime is a concurrent transaction processor.&#x20;

Transactions specify their data dependencies upfront and dynamic memory allocation is explicit. By separating program code from the state it operates on, the runtime is able to choreograph concurrent access.&#x20;

Transactions accessing only read-only accounts are executed in parallel whereas transactions accessing writable accounts are serialized.&#x20;

The runtime interacts with the program through an entrypoint with a well-defined interface.&#x20;

The data stored in an account is an opaque type, an array of bytes. The program has full control over its contents.

The transaction structure specifies a list of public keys and signatures for those keys and a sequential list of instructions that will operate over the states associated with the account keys.&#x20;

For the transaction to be committed all the instructions must execute successfully; if any abort the whole transaction fails to commit.

Account Structure

​Accounts maintain a lamport balance and program-specific memory.

## Transaction Engine

​The engine maps public keys to accounts and routes them to the program's entrypoint.

### Execution​

Transactions are batched and processed in a pipeline.&#x20;

The TPU and TVU follow a slightly different path.&#x20;

The TPU runtime ensures that PoH record occurs before memory is committed.

The TVU runtime ensures that PoH verification occurs before the runtime processes any transactions.

<figure><img src="/files/aUksk8LL6tpgQ7Y8YH1H" alt=""><figcaption></figcaption></figure>

At the execute stage, the loaded accounts have no data dependencies, so all the programs can be executed in parallel.

The runtime enforces the following rules:

1. Only the *owner* program may modify the contents of an account. This means that upon assignment data vector is guaranteed to be zero.
2. Total balances on all the accounts is equal before and after execution of a transaction.
3. After the transaction is executed, balances of read-only accounts must be equal to the balances before the transaction.
4. All instructions in the transaction executed atomically. If one fails, all account modifications are discarded.

Execution of the program involves mapping the program's public key to an entrypoint which takes a pointer to the transaction, and an array of loaded accounts.

### **SystemProgram Interface**

The interface is best described by the `Instruction::data` that the user encodes.

* `CreateAccount` - This allows the user to create an account with an allocated data array and assign it to a Program.
* `CreateAccountWithSeed` - Same as `CreateAccount`, but the new account's address is derived from
  * the funding account's pubkey,
  * a mnemonic string (seed), and
  * the pubkey of the Program
* `Assign` - Allows the user to assign an existing account to a program.
* `Transfer` - Transfers lamports between accounts.

### **Program State Security**

For blockchain to function correctly, the program code must be resilient to user inputs.&#x20;

That is why in this design the program specific code is the only code that can change the state of the data byte array in the Accounts that are assigned to it.&#x20;

It is also the reason why `Assign` or `CreateAccount` must zero out the data.&#x20;

Otherwise there would be no possible way for the program to distinguish the recently assigned account data from a natively generated state transition without some additional metadata from the runtime to indicate that this memory is assigned instead of natively generated.

To pass messages between programs, the receiving program must accept the message and copy the state over. But in practice a copy isn't needed and is undesirable.&#x20;

The receiving program can read the state belonging to other Accounts without copying it, and during the read it has a guarantee of the sender program's state.

### **Notes**

* There is no dynamic memory allocation. Client's need to use `CreateAccount` instructions to create memory before passing it to another program. This instruction can be composed into a single transaction with the call to the program itself.
* `CreateAccount` and `Assign` guarantee that when account is assigned to the program, the Account's data is zero initialized.
* Transactions that assign an account to a program or allocate space must be signed by the Account address' private key unless the Account is being created by `CreateAccountWithSeed`, in which case there is no corresponding private key for the account's address/pubkey.
* Once assigned to program an Account cannot be reassigned.
* Runtime guarantees that a program's code is the only code that can modify Account data that the Account is assigned to.
* Runtime guarantees that the program can only spend lamports that are in accounts that are assigned to it.
* Runtime guarantees the balances belonging to accounts are balanced before and after the transaction.
* Runtime guarantees that instructions all executed successfully when a transaction is committed.


# CLI


# Command-line Guide

## Command-line Guide

In this section, we will describe how to use the PUT command-line tools to create a wallet, to send and receive PUT tokens, and to participate in the cluster by delegating stake.

To interact with a PUT cluster, we will use its command-line interface, also known as the CLI.&#x20;

We use the command-line because it is the first place the PUT core team deploys new functionality.&#x20;

The command-line interface is not necessarily the easiest to use, but it provides the most direct, flexible, and secure access to your PUT accounts.

## Getting Started

To get started using the PUT Command Line (CLI) tools:

Install the PUT Tools&#x20;

Choose a Cluster&#x20;

Create a Wallet&#x20;

Check out our CLI conventions


# Install the PUT Tool Suite

## Install the PUT Tool Suite

There are multiple ways to install the PUT tools on your computer depending on your preferred workflow:

* Download Prebuilt Binaries
* Build from Source

## Download Prebuilt Binaries

You can manually download and install the binaries for Ubuntu 20.04 LTS.

### Linux

Download the laste binaries: [put\_v1.0.0.tar.gz](https://pub-block-n.s3.ap-east-1.amazonaws.com/put/put_v1.0.0.tar.gz),then extract the archive:

```
tar xzf put_v1.0.0.tar.gz
cd put/
export PATH=$PWD/bin:$PATH
```

### MacOS\[NOT YET SUPPORT]

### Windows\[NOT YET SUPPORT]

## Build From Source\[NOT YET SUPPORT]

##


# Command-line Wallets


# Command Line Wallets

## Command Line Wallets

PUT supports several different types of wallets that can be used to interface directly with the PUT command-line tools.

To use a Command Line Wallet, you must first install the PUT CLI tools

## File System Wallet

A file system wallet, aka an FS wallet, is a directory in your computer's file system.&#x20;

Each file in the directory holds a keypair.

### File System Wallet Security

A file system wallet is the most convenient and least secure form of wallet. It is convenient because the keypair is stored in a simple file.

You can generate as many keys as you would like and trivially back them up by copying the files.

It is insecure because the keypair files are unencrypted.&#x20;

If you are the only user of your computer and you are confident it is free of malware, an FS wallet is a fine solution for small amounts of cryptocurrency.&#x20;

If, however, your computer contains malware and is connected to the Internet, that malware may upload your keys and use them to take your tokens.&#x20;

Likewise, because the keypairs are stored on your computer as files, a skilled hacker with physical access to your computer may be able to access it.&#x20;

Using an encrypted hard drive, such as FileVault on MacOS, minimizes that risk.

File System Wallet

## Paper Wallet

A paper wallet is a collection of seed phrases written on paper.&#x20;

A seed phrase is some number of words (typically 12 or 24) that can be used to regenerate a keypair on demand.

### Paper Wallet Security

In terms of convenience versus security, a paper wallet sits at the opposite side of the spectrum from an FS wallet.&#x20;

It is terribly inconvenient to use, but offers excellent security.&#x20;

That high security is further amplified when paper wallets are used in conjunction with offline signing.


# Paper Wallet

## Paper Wallet

This document describes how to create and use a paper wallet with the PUT CLI tools.

We do not intend to advise on how to securely create or manage paper wallets.&#x20;

Please research the security concerns carefully.

## Overview

PUT provides a key generation tool to derive keys from BIP39-compliant seed phrases.&#x20;

PUT CLI commands for running a validator and staking tokens all support keypair input via seed phrases.

## Paper Wallet Usage

PUT commands can be run without ever saving a keypair to disk on a machine.

&#x20;If avoiding writing a private key to disk is a security concern of yours, you've come to the right place.

Even using this secure input method, it's still possible that a private key gets written to disk by unencrypted memory swaps.

&#x20;It is the user's responsibility to protect against this scenario.

## Before You Begin

```
Install the Put command-line tools
```

### Check your installation

Check that put-keygen is installed correctly by running:

```
put-keygen --version
```

## Creating a Paper Wallet

Using the put-keygen tool, it is possible to generate new seed phrases as well as derive a keypair from an existing seed phrase and (optional) passphrase.&#x20;

The seed phrase and passphrase can be used together as a paper wallet.&#x20;

As long as you keep your seed phrase and passphrase stored safely, you can use them to access your account.

For more information about how seed phrases work, review this Bitcoin Wiki page.

### Seed Phrase Generation

Generating a new keypair can be done using the put-keygen new command.&#x20;

The command will generate a random seed phrase, ask you to enter an optional passphrase, and then will display the derived public key and the generated seed phrase for your paper wallet.

After copying down your seed phrase, you can use the public key derivation instructions to verify that you have not made any errors.

```
put-keygen new --no-outfile
```

If the --no-outfile flag is omitted, the default behavior is to write the keypair to \~/.config/put/id.json, resulting in a file system wallet.

The output of this command will display a line like this:

```
pubkey: 9ZNTfG4NyQgxy2SWjSiQoUyBPEvXT2xo7fKc5hPYYJ7b
```

The value shown after pubkey: is your wallet address.

Note: In working with paper wallets and file system wallets, the terms "pubkey" and "wallet address" are sometimes used interchangably.

For added security, increase the seed phrase word count using the --word-count argument

For full usage details, run:

```
put-keygen new --help
```

### Public Key Derivation

Public keys can be derived from a seed phrase and a passphrase if you choose to use one. This is useful for using an offline-generated seed phrase to derive a valid public key.&#x20;

The put-keygen pubkey command will walk you through how to use your seed phrase (and a passphrase if you chose to use one) as a signer with the put command-line tools using the prompt URI scheme.

```
put-keygen pubkey prompt://
```

Note that you could potentially use different passphrases for the same seed phrase. Each unique passphrase will yield a different keypair.

The put-keygen tool uses the same BIP39 standard English word list as it does to generate seed phrases.&#x20;

If your seed phrase was generated with another tool that uses a different word list, you can still use put-keygen, but will need to pass the --skip-seed-phrase-validation argument and forego this validation.

```
put-keygen pubkey prompt:// --skip-seed-phrase-validation
```

After entering your seed phrase with put-keygen pubkey prompt:// the console will display a string of base-58 characters.&#x20;

This is the derived put BIP44 wallet address associated with your seed phrase.

Copy the derived address to a USB stick for easy usage on networked computers

If needed, you can access the legacy, raw keypair's pubkey by instead passing the ASK keyword:

```
put-keygen pubkey ASK
```

A common next step is to check the balance of the account associated with a public key

For full usage details, run:

```
put-keygen pubkey --help
```

### Hierarchical Derivation

The put-cli supports BIP32 and BIP44 hierarchical derivation of private keys from your seed phrase and passphrase by adding either the ?key= query string or the ?full-path= query string.

By default, prompt: will derive put's base derivation path m/44'/501'. To derive a child key, supply the ?key=/ query string.

```
put-keygen pubkey prompt://?key=0/1
```

To use a derivation path other than put's standard BIP44, you can supply ?full-path=m//\<COIN\_TYPE>//.

```
put-keygen pubkey prompt://?full-path=m/44/2017/0/1
```

Because Put uses Ed25519 keypairs, as per SLIP-0010 all derivation-path indexes will be promoted to hardened indexes -- eg. ?key=0'/0', ?full-path=m/44'/2017'/0'/1' -- regardless of whether ticks are included in the query-string input.

## Verifying the Keypair

To verify you control the private key of a paper wallet address, use put-keygen verify:

```
put-keygen verify <PUBKEY> prompt://
```

where is replaced with the wallet address and the keyword prompt:// tells the command to prompt you for the keypair's seed phrase; key and full-path query-strings accepted.&#x20;

Note that for security reasons, your seed phrase will not be displayed as you type.&#x20;

After entering your seed phrase, the command will output "Success" if the given public key matches the keypair generated from your seed phrase, and "Failed" otherwise.

## Checking Account Balance

All that is needed to check an account balance is the public key of an account.&#x20;

To retrieve public keys securely from a paper wallet, follow the Public Key Derivation instructions on an air gapped computer.&#x20;

Public keys can then be typed manually or transferred via a USB stick to a networked machine.

Next, configure the put CLI tool to connect to a particular cluster:

```
put config set --url <CLUSTER URL> # (i.e. https://api.mainnet-beta.put.com)
```

Finally, to check the balance, run the following command:

```
put balance <PUBKEY>
```

## Creating Multiple Paper Wallet Addresses

You can create as many wallet addresses as you like.

&#x20;Simply re-run the steps in Seed Phrase Generation or Public Key Derivation to create a new address.&#x20;

Multiple wallet addresses can be useful if you want to transfer tokens between your own accounts for different purposes.

## Support

Check out our Wallet Support Page for ways to get help.


# File System Wallet

## File System Wallet

This document describes how to create and use a file system wallet with the PUT CLI tools.&#x20;

A file system wallet exists as an unencrypted keypair file on your computer system's filesystem.

File system wallets are the least secure method of storing PUT tokens.&#x20;

Storing large amounts of tokens in a file system wallet is not recommended.

## Before you Begin

Make sure you have installed the PUT Command Line Tools

## Generate a File System Wallet Keypair

Use PUT's command-line tool put-keygen to generate keypair files.&#x20;

For example, run the following from a command-line shell:

```
mkdir ~/my-put-wallet
put-keygen new --outfile ~/my-put-wallet/my-keypair.json
```

This file contains your unencrypted keypair. In fact, even if you specify a password, that password applies to the recovery seed phrase, not the file.&#x20;

Do not share this file with others. Anyone with access to this file will have access to all tokens sent to its public key.&#x20;

Instead, you should share only its public key. To display its public key, run:

```
put-keygen pubkey ~/my-put-wallet/my-keypair.json
```

It will output a string of characters, such as:

```
ErRr1caKzK8L8nn4xmEWtimYRiTCAZXjBtVphuZ5vMKy
```

This is the public key corresponding to the keypair in \~/my-put-wallet/my-keypair.json.&#x20;

The public key of the keypair file is your wallet address.

## Verify your Address against your Keypair file

To verify you hold the private key for a given address, use put-keygen verify:

```
put-keygen verify <PUBKEY> ~/my-put-wallet/my-keypair.json
```

where is replaced with your wallet address.&#x20;

The command will output "Success" if the given address matches the one in your keypair file, and "Failed" otherwise.

## Creating Multiple File System Wallet Addresses

You can create as many wallet addresses as you like.&#x20;

Simply re-run the steps in Generate a File System Wallet and make sure to use a new filename or path with the --outfile argument.&#x20;

Multiple wallet addresses can be useful if you want to transfer tokens between your own accounts for different purposes.


# Support / Troubleshooting

Support / Troubleshooting

If you have questions or are having trouble setting up or using your wallet of choice, please make sure you've read through all the relevant pages in our Wallet Guide.&#x20;

The PUT team is working hard to support new features on popular wallets, and we do our best to keep our documents up to date with the latest available features.

If you have questions after reading the docs, feel free to reach out to us on our Telegram.

For technical support, please ask a question on StackOverflow and tag your questions with PUT.


# Using PUT CLI

## Using PUT CLI

Before running any PUT CLI commands, let's go over some conventions that you will see across all commands.&#x20;

First, the PUT CLI is actually a collection of different commands for each action you might want to take. You can view the list of all possible commands by running:

```
put --help
```

To zoom in on how to use a particular command, run:

```
put <COMMAND> --help
```

where you replace the text with the name of the command you want to learn more about.

The command's usage message will typically contain words such as , \<ACCOUNT\_ADDRESS> or .&#x20;

Each word is a placeholder for the type of text you can execute the command with. For example, you can replace with a number such as 42 or 100.42.&#x20;

You can replace \<ACCOUNT\_ADDRESS> with the base58 encoding of your public key, such as 9grmKMwTiZwUHSExjtbFzHLPTdWoXgcg1bZkhvwTrTww.

## Keypair conventions

Many commands using the CLI tools require a value for a . The value you should use for the keypair depends on what type of command line wallet you created.

For example, the CLI help shows that the way to display any wallet's address (also known as the keypair's pubkey), is:

```
put-keygen pubkey <KEYPAIR>
```

Below, we show how to resolve what you should PUT in depending on your wallet type.

## Paper Wallet

In a paper wallet, the keypair is securely derived from the seed words and optional passphrase you entered when the wallet was created.&#x20;

To use a paper wallet keypair anywhere the text is shown in examples or help documents, enter the uri scheme prompt:// and the program will prompt you to enter your seed words when you run the command.

To display the wallet address of a Paper Wallet:

```
put-keygen pubkey prompt://
```

## File System Wallet\#

With a file system wallet, the keypair is stored in a file on your computer. Replace with the complete file path to the keypair file.

For example, if the file system keypair file location is /home/put/my\_wallet.json, to display the address, do:

```
put-keygen pubkey /home/put/my_wallet.json
```


# Connecting to a Cluster

Connecting to a Cluster

See PUT Clusters for general information about the available clusters.

## Configure the command-line tool

You can check what cluster the PUT command-line tool (CLI) is currently targeting by running the following command:

```
put config get
```

Use put config set command to target a particular cluster.&#x20;

After setting a cluster target, any future subcommands will send/receive information from that cluster.

For example to target the Devnet cluster, run:

```
put config set --url https://rpc.putdev.com:8889
```

## Ensure Versions Match

Though not strictly necessary, the CLI will generally work best when its version matches the software version running on the cluster.&#x20;

To get the locally-installed CLI version, run:

```
put --version
```

To get the cluster version, run:

```
put cluster-version
```

Ensure the local CLI version is greater than or equal to the cluster version.


# Send and Receive Tokens

Send and Receive Tokens

This page decribes how to receive and send PUT tokens using the command line tools with a command line wallet such as a paper wallet, a file system wallet, or a hardware wallet.&#x20;

Before you begin, make sure you have created a wallet and have access to its address (pubkey) and the signing keypair.&#x20;

Check out our conventions for entering keypairs for different wallet types.

## Testing your Wallet\#

Before sharing your public key with others, you may want to first ensure the key is valid and that you indeed hold the corresponding private key.

In this example, we will create a second wallet in addition to your first wallet, and then transfer some tokens to it.&#x20;

This will confirm that you can send and receive tokens on your wallet type of choice.

This test example uses our Developer Testnet, called devnet.&#x20;

Tokens issued on devnet have no value, so don't worry if you lose them.

## Airdrop some tokens to get started

First, airdrop yourself some play tokens on the devnet.

```
put airdrop 1 <RECIPIENT_ACCOUNT_ADDRESS> --url https://rpc.putdev.com:8889
```

where you replace the text \<RECIPIENT\_ACCOUNT\_ADDRESS> with your base58-encoded public key/wallet address.

A response with the signature of the transaction will be returned.&#x20;

If the balance of the address does not change by the expected amount, run the following command for more information on what potentially went wrong:

```
put confirm -v <TRANSACTION_SIGNATURE>
```

Check your balance#

Confirm the airdrop was successful by checking the account's balance. It should output 1 PUT:

```
put balance <ACCOUNT_ADDRESS> --url https://rpc.putdev.com:8889
```

## Create a second wallet address

We will need a new address to receive our tokens. Create a second keypair and record its pubkey:

```
put-keygen new --no-passphrase --no-outfile
```

The output will contain the address after the text pubkey:. Copy the address. We will use it in the next step.

```
pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV
```

You can also create a second (or more) wallet of any type: paper, file system, or hardware. Transfer tokens from your first wallet to the second address#

Next, prove that you own the airdropped tokens by transferring them.&#x20;

The Solana cluster will only accept the transfer if you sign the transaction with the private keypair corresponding to the sender's public key in the transaction.

```
put transfer --from <KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> 0.5 --allow-unfunded-recipient --url https://rpc.putdev.com:8889 --fee-payer <KEYPAIR>
```

where you replace with the path to a keypair in your first wallet, and replace \<RECIPIENT\_ACCOUNT\_ADDRESS> with the address of your second wallet.

Confirm the updated balances with put balance:

```
put balance <ACCOUNT_ADDRESS> --url https://rpc.putdev.com:8889
```

where \<ACCOUNT\_ADDRESS> is either the public key from your keypair or the recipient's public key.

## Full example of test transfer

```
$ put-keygen new --outfile my_put_wallet.json   # Creating my first wallet, a file system wallet
Generating a new keypair
For added security, enter a passphrase (empty for no passphrase):
Wrote new keypair to my_put_wallet.json
==========================================================================
pubkey: DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK                          # Here is the address of the first wallet
==========================================================================
Save this seed phrase to recover your new keypair:
width enhance concert vacant ketchup eternal spy craft spy guard tag punch    # If this was a real wallet, never share these words on the internet like this!
==========================================================================

$ put airdrop 1 DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK --url https://rpc.putdev.com:8889  # Airdropping 1 PUT to my wallet's address/pubkey
Requesting airdrop of 1 PUT from 35.233.193.70:9900
1 PUT

$ put balance DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK --url https://rpc.putdev.com:8889 # Check the address's balance
1 PUT

$ put-keygen new --no-outfile  # Creating a second wallet, a paper wallet
Generating a new keypair
For added security, enter a passphrase (empty for no passphrase):
====================================================================
pubkey: 7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv                   # Here is the address of the second, paper, wallet.
====================================================================
Save this seed phrase to recover your new keypair:
clump panic cousin hurt coast charge engage fall eager urge win love   # If this was a real wallet, never share these words on the internet like this!
====================================================================

$ put transfer --from my_put_wallet.json 7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv 0.5 --allow-unfunded-recipient --url https://rpc.putdev.com:8889 --fee-payer my_put_wallet.json  # Transferring tokens to the public address of the paper wallet
3gmXvykAd1nCQQ7MjosaHLf69Xyaqyq1qw2eu1mgPyYXd5G4v1rihhg1CiRw35b9fHzcftGKKEu4mbUeXY2pEX2z  # This is the transaction signature

$ put balance DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK --url https://rpc.putdev.com:8889
0.499995 PUT  # The sending account has slightly less than 0.5 PUT remaining due to the 0.000005 PUT transaction fee payment

$ put balance 7S3P4HxJpyyigGzodYwHtCxZyUQe9JiBMHyRWXArAaKv --url https://rpc.putdev.com:8889
0.5 PUT  # The second wallet has now received the 0.5 PUT transfer from the first wallet
```

## Receive Tokens

To receive tokens, you will need an address for others to send tokens to.&#x20;

In PUT, the wallet address is the public key of a keypair.&#x20;

There are a variety of techniques for generating keypairs.&#x20;

The method you choose will depend on how you choose to store keypairs. Keypairs are stored in wallets.&#x20;

Before receiving tokens, you will need to create a wallet. Once completed, you should have a public key for each keypair you generated.&#x20;

The public key is a long string of base58 characters. Its length varies from 32 to 44 characters.

## Send Tokens

If you already hold PUT and want to send tokens to someone, you will need a path to your keypair, their base58-encoded public key, and a number of tokens to transfer.

Once you have that collected, you can transfer tokens with the put transfer command:

```
put transfer --from <KEYPAIR> <RECIPIENT_ACCOUNT_ADDRESS> <AMOUNT> --fee-payer <KEYPAIR>
```

Confirm the updated balances with put balance:

```
put balance <ACCOUNT_ADDRESS>
```


# Staking

## Staking

After you have received PUT, you might consider putting it to use by delegating stake to a validator. Stake is what we call tokens in a stake account.&#x20;

PUT weights validator votes by the amount of stake delegated to them, which gives those validators more influence in determining then next valid block of transactions in the blockchain.&#x20;

PUT then generates new PUT periodically to reward stakers and validators.&#x20;

You earn more rewards the more stake you delegate.

## Create a Stake Account

To delegate stake, you will need to transfer some tokens into a stake account.&#x20;

To create an account, you will need a keypair. Its public key will be used as the stake account address.&#x20;

No need for a password or encryption here; this keypair will be discarded right after creating the stake account.

```
put-keygen new --no-passphrase -o stake-account.json
```

The output will contain the public key after the text pubkey:.

```
pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV
```

Copy the public key and store it for safekeeping.&#x20;

You will need it any time you want to perform an action on the stake account you create next.

Now, create a stake account:

```
put create-stake-account --from <KEYPAIR> stake-account.json <AMOUNT> \
    --stake-authority <KEYPAIR> --withdraw-authority <KEYPAIR> \
    --fee-payer <KEYPAIR>
```

tokens are transferred from the account at the "from" to a new stake account at the public key of stake-account.json.

The stake-account.json file can now be discarded.&#x20;

To authorize additional actions, you will use the --stake-authority or --withdraw-authority keypair, not stake-account.json.

View the new stake account with the put stake-account command:

```
put stake-account <STAKE_ACCOUNT_ADDRESS>
```

The output will look similar to this:

```
Total Stake: 5000 PUT
Stake account is undelegated
Stake Authority: EXU95vqs93yPeCeAU7mPPu6HbRUmTFPEiGug9oCdvQ5F
Withdraw Authority: EXU95vqs93yPeCeAU7mPPu6HbRUmTFPEiGug9oCdvQ5F
```

### Set Stake and Withdraw Authorities

Stake and withdraw authorities can be set when creating an account via the --stake-authority and --withdraw-authority options, or afterward with the PUT stake-authorize command. For example, to set a new stake authority, run:

```
put stake-authorize <STAKE_ACCOUNT_ADDRESS> \
    --stake-authority <KEYPAIR> --new-stake-authority <PUBKEY> \
    --fee-payer <KEYPAIR>
```

This will use the existing stake authority to authorize a new stake authority on the stake account \<STAKE\_ACCOUNT\_ADDRESS>.

### Advanced: Derive Stake Account Addresses

When you delegate stake, you delegate all tokens in the stake account to a single validator. To delegate to multiple validators, you will need multiple stake accounts. Creating a new keypair for each account and managing those addresses can be cumbersome. Fortunately, you can derive stake addresses using the --seed option:

```
put create-stake-account --from <KEYPAIR> <STAKE_ACCOUNT_KEYPAIR> --seed <STRING> <AMOUNT> \
--stake-authority <PUBKEY> --withdraw-authority <PUBKEY> --fee-payer <KEYPAIR>
```

is an arbitrary string up to 32 bytes, but will typically be a number corresponding to which derived account this is. The first account might be "0", then "1", and so on. The public key of \<STAKE\_ACCOUNT\_KEYPAIR> acts as the base address. The command derives a new address from the base address and seed string. To see what stake address the command will derive, use put create-address-with-seed:

```
put create-address-with-seed --from <PUBKEY> <SEED_STRING> STAKE
```

is the public key of the \<STAKE\_ACCOUNT\_KEYPAIR> passed to put create-stake-account.

The command will output a derived address, which can be used for the \<STAKE\_ACCOUNT\_ADDRESS> argument in staking operations.

## Delegate Stake

To delegate your stake to a validator, you will need its vote account address. Find it by querying the cluster for the list of all validators and their vote accounts with the put validators command:

```
put validators
```

The first column of each row contains the validator's identity and the second is the vote account address. Choose a validator and use its vote account address in put delegate-stake:

```
put delegate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <VOTE_ACCOUNT_ADDRESS> \
    --fee-payer <KEYPAIR>
```

The stake authority authorizes the operation on the account with address \<STAKE\_ACCOUNT\_ADDRESS>. The stake is delegated to the vote account with address \<VOTE\_ACCOUNT\_ADDRESS>.

After delegating stake, use put stake-account to observe the changes to the stake account:

```
put stake-account <STAKE_ACCOUNT_ADDRESS>
```

You will see new fields "Delegated Stake" and "Delegated Vote Account Address" in the output. The output will look similar to this:

```
Total Stake: 5000 PUT
Credits Observed: 147462
Delegated Stake: 4999.99771712 PUT
Delegated Vote Account Address: CcaHc2L43ZWjwCHART3oZoJvHLAe9hzT2DJNUpBzoTN1
Stake activates starting from epoch: 42
Stake Authority: EXU95vqs93yPeCeAU7mPPu6HbRUmTFPEiGug9oCdvQ5F
Withdraw Authority: EXU95vqs93yPeCeAU7mPPu6HbRUmTFPEiGug9oCdvQ5F
```

## Deactivate Stake

Once delegated, you can undelegate stake with the put deactivate-stake command:

```
put deactivate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> \
    --fee-payer <KEYPAIR>
```

The stake authority authorizes the operation on the account with address \<STAKE\_ACCOUNT\_ADDRESS>.

Note that stake takes several epochs to "cool down". Attempts to delegate stake in the cool down period will fail.

## Withdraw Stake

Transfer tokens out of a stake account with the put withdraw-stake command:

```
put withdraw-stake --withdraw-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS> <AMOUNT> \
    --fee-payer <KEYPAIR>
```

\<STAKE\_ACCOUNT\_ADDRESS> is the existing stake account, the stake authority is the withdraw authority, and is the number of tokens to transfer to \<RECIPIENT\_ADDRESS>.

## Split Stake

You may want to delegate stake to additional validators while your existing stake is not eligible for withdrawal. It might not be eligible because it is currently staked, cooling down, or locked up. To transfer tokens from an existing stake account to a new one, use the put split-stake command:

```
put split-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <NEW_STAKE_ACCOUNT_KEYPAIR> <AMOUNT> \
    --fee-payer <KEYPAIR>
```

\<STAKE\_ACCOUNT\_ADDRESS> is the existing stake account, the stake authority is the stake authority, \<NEW\_STAKE\_ACCOUNT\_KEYPAIR> is the keypair for the new account, and is the number of tokens to transfer to the new account.

To split a stake account into a derived account address, use the --seed option. See Derive Stake Account Addresses for details.


# Deploy a Program

## Deploy a Program

Developers can deploy on-chain programs (often called smart contracts elsewhere) with the PUT tools.

To learn about developing and executing programs on PUT, start with the intro to PUT programs and then dig into the details of on-chain programs.

To deploy a program, use the PUT tools to interact with the on-chain loader to:

Initialize a program account Upload the program's shared object to the program account's data buffer Verify the uploaded program Finalize the program by marking the program account executable.

Once deployed, anyone can execute the program by sending transactions that reference it to the cluster.

## Usage\#

### Deploy a program

To deploy a program, you will need the location of the program's shared object (the program binary .so)

```
put program deploy <PROGRAM_FILEPATH>
```

Successful deployment will return the program id of the deployed program, for example:

```
Program Id: 3KS2k14CmtnuVv2fvYcvdrNgC94Y11WETBpMUGgXyWZL
```

Specify the keypair in the deploy command to deploy to a specific program id:

```
put program deploy --program-id <KEYPAIR_FILEPATH> <PROGRAM_FILEPATH>
```

If the program id is not specified on the command line the tools will first look for a keypair file matching the \<PROGRAM\_FILEPATH>, or internally generate a new keypair.

A matching program keypair file is in the same directory as the program's shared object, and named \<PROGRAM\_NAME>-keypair.json. Matching program keypairs are generated automatically by the program build tools:

```
./path-to-program/program.so
./path-to-program/program-keypair.json
```

### Showing a program account

To get information about a deployed program:

```
put program show <ACCOUNT_ADDRESS>
```

An example output looks like:

```
Program Id: 3KS2k14CmtnuVv2fvYcvdrNgC94Y11WETBpMUGgXyWZL
Owner: BPFLoaderUpgradeab1e11111111111111111111111
ProgramData Address: EHsACWBhgmw8iq5dmUZzTA1esRqcTognhKNHUkPi4q4g
Authority: FwoGJNUaJN2zfVEex9BB11Dqb3NJKy3e9oY3KTh9XzCU
Last Deployed In Slot: 63890568
Data Length: 5216 (0x1460) bytes
```

Program Id is the address that can be referenced in an instruction's program\_id field when invoking a program.

Owner: The loader this program was deployed with.

ProgramData Address is the account associated with the program account that holds the program's data (shared object).

Authority is the program's upgrade authority.

Last Deployed In Slot is the slot in which the program was last deployed.

Data Length is the size of the space reserved for deployments. The actual space used by the currently deployed program may be less.

### Redeploy a program

A program can be redeployed to the same address to facilitate rapid development, bug fixes, or upgrades. Matching keypair files are generated once so that redeployments will be to the same program address.

The command looks the same as the deployment command:

```
put program deploy <PROGRAM_FILEPATH>
```

By default, programs are deployed to accounts that are twice the size of the original deployment.&#x20;

Doing so leaves room for program growth in future redeployments.&#x20;

But, if the initially deployed program is very small (like a simple helloworld program) and then later grows substantially, the redeployment may fail.&#x20;

To avoid this, specify a max\_len that is at least the size (in bytes) that the program is expected to become (plus some wiggle room).

```
put program deploy --max-len 200000 <PROGRAM_FILEPATH>
```

Note that program accounts are required to be rent-exempt, and the max-len is fixed after initial deployment, so any PUT in the program accounts is locked up permanently.

### Resuming a failed deploy

If program deployment fails, there will be a hanging intermediate buffer account that contains a non-zero balance.&#x20;

In order to recoup that balance you may resume a failed deployment by providing the same intermediate buffer to a new call to deploy.

Deployment failures will print an error message specifying the seed phrase needed to recover the generated intermediate buffer's keypair:

```
==================================================================================
Recover the intermediate account's ephemeral keypair file with
`put-keygen recover` and the following 12-word seed phrase:
==================================================================================
valley flat great hockey share token excess clever benefit traffic avocado athlete
==================================================================================
To resume a deploy, pass the recovered keypair as
the [BUFFER_SIGNER] to `put program deploy` or `put program write-buffer'.
Or to recover the account's lamports, pass it as the
[BUFFER_ACCOUNT_ADDRESS] argument to `put program drain`.
==================================================================================
```

To recover the keypair:

```
put-keygen recover -o <KEYPAIR_PATH>
```

When asked, enter the 12-word seed phrase.

Then issue a new deploy command and specify the buffer:

```
put program deploy --buffer <KEYPAIR_PATH> <PROGRAM_FILEPATH>
```

### Closing program and buffer accounts, and reclaiming their lamports

Both program and buffer accounts can be closed and their lamport balances transferred to a recipient's account.

If deployment fails there will be a left over buffer account that holds lamports.&#x20;

The buffer account can either be used to resume a deploy or closed.

The program or buffer account's authority must be present to close an account, to list all the open program or buffer accounts that match the default authority:

```
put program show --programs
put program show --buffers
```

To specify a different authority:

```
put program show --programs --buffer-authority <AURTHORITY_ADRESS>
put program show --buffers --buffer-authority <AURTHORITY_ADRESS>
```

To close a single account: put program close

To close a single account and specify a different authority than the default:

```
put program close <ADDRESS> --buffer-authority <KEYPAIR_FILEPATH>
```

To close a single account and specify a different recipient than the default:

```
put program close <ADDRESS> --recipient <RECIPIENT_ADDRESS>
```

To close all the buffer accounts associated with the current authority:

```
put program close --buffers
```

To show all buffer accounts regardless of the authority

```
put program show --buffers --all
```

### Set a program's upgrade authority

The program's upgrade authority must to be present to deploy a program. If no authority is specified during program deployment, the default keypair is used as the authority.&#x20;

This is why redeploying a program in the steps above didn't require an authority to be explicitly specified.

The authority can be specified during deployment:

```
put program deploy --upgrade-authority <UPGRADE_AUTHORITY_SIGNER> <PROGRAM_FILEPATH>
```

Or after deployment and using the default keypair as the current authority:

```
put program set-upgrade-authority <PROGRAM_ADDRESS> --new-upgrade-authority <NEW_UPGRADE_AUTHORITY>
```

Or after deployment and specifying the current authority:

```
put program set-upgrade-authority <PROGRAM_ADDRESS> --upgrade-authority <UPGRADE_AUTHORITY_SIGNER> --new-upgrade-authority <NEW_UPGRADE_AUTHORITY>
```

### Immutable programs

A program can be marked immutable, which prevents all further redeployments, by specifying the --final flag during deployment:

```
put program deploy <PROGRAM_FILEPATH> --final
```

Or anytime after:

```
put program set-upgrade-authority <PROGRAM_ADDRESS> --final
```

### Dumping a program to a file

The deployed program may be dumped back to a local file:

```
put program dump <ACCOUNT_ADDRESS> <OUTPUT_FILEPATH>
```

The dumped file will be in the same as what was deployed, so in the case of a shared object, the dumped file will be a fully functional shared object.&#x20;

Note that the dump command dumps the entire data space, which means the output file will have trailing zeros after the shared object's data up to max\_len.&#x20;

Sometimes it is useful to dump and compare a program to ensure it matches a known program binary.&#x20;

The original program file can be zero-extended, hashed, and compared to the hash of the dumped file.

```
$ put dump <ACCOUNT_ADDRESS> dump.so
$ cp original.so extended.so
$ truncate -r dump.so extended.so
$ sha256sum extended.so dump.so
```

### Using an intermediary Buffer account

Instead of deploying directly to the program account, the program can be written to an intermediary buffer account.&#x20;

Intermediary accounts can be useful for things like multi-entity governed programs where the governing members fist verify the intermediary buffer contents and then vote to allow an upgrade using it.

```
put program write-buffer <PROGRAM_FILEPATH>
```

Buffer accounts support authorities like program accounts:

```
put program set-buffer-authority <BUFFER_ADDRESS> --new-buffer-authority <NEW_BUFFER_AUTHORITY>
```

One exception is that buffer accounts cannot be marked immutable like program accounts can, so they don't support --final.

The buffer account, once entirely written, can be passed to deploy to deploy the program:

```
put program deploy --program-id <PROGRAM_ADDRESS> --buffer <BUFFER_ADDRESS>
```

Note, the buffer's authority must match the program's upgrade authority.

Buffers also support show and dump just like programs do.

{% hint style="info" %}
Warm reminder:&#x20;

If the contract release is unsuccessful due to network timeout, please switch the release network to the European region before releasing the contract.
{% endhint %}


# Offline Transaction Signing

## Offline Transaction Signing

Some security models require keeping signing keys, and thus the signing process, separated from transaction creation and network broadcast.&#x20;

Examples include:

* Collecting signatures from geographically disparate signers in a multi-signature scheme
* Signing transactions using an airgapped signing device

This document describes using PUT's CLI to separately sign and submit a transaction.

## Commands Supporting Offline Signing\#

At present, the following commands support offline signing:

* `create-stake-account`
* `create-stake-account-checked`
* `deactivate-stake`
* `delegate-stake`
* `split-stake`
* `stake-authorize`
* `stake-authorize-checked`
* `stake-set-lockup`
* `stake-set-lockup-checked`
* `transfer`
* `withdraw-stake`
* `create-vote-account`
* `vote-authorize-voter`
* `vote-authorize-voter-checked`
* `vote-authorize-withdrawer`
* `vote-authorize-withdrawer-checked`
* `vote-update-commission`
* `vote-update-validator`
* `withdraw-from-vote-account`

## Signing Transactions Offline

To sign a transaction offline, pass the following arguments on the command line

1. `--sign-only`, prevents the client from submitting the signed transaction to the network. Instead, the pubkey/signature pairs are printed to stdout.
2. `--blockhash BASE58_HASH`, allows the caller to specify the value used to fill the transaction's `recent_blockhash` field. This serves a number of purposes, namely: *Eliminates the need to connect to the network and query a recent blockhash via RPC* Enables the signers to coordinate the blockhash in a multiple-signature scheme

### Example: Offline Signing a Payment

Command

```
put@offline$ put transfer --sign-only --blockhash 5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF \
    recipient-keypair.json 1
```

Output

```
Blockhash: 5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF
Signers (Pubkey=Signature):
  FhtzLVsmcV7S5XqGD79ErgoseCLhZYmEZnz9kQg1Rp7j=4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN

{"blockhash":"5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF","signers":["FhtzLVsmcV7S5XqGD79ErgoseCLhZYmEZnz9kQg1Rp7j=4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN"]}'
```

## Submitting Offline Signed Transactions to the Network

To submit a transaction that has been signed offline to the network, pass the following arguments on the command line

1. `--blockhash BASE58_HASH`, must be the same blockhash as was used to sign
2. `--signer BASE58_PUBKEY=BASE58_SIGNATURE`, one for each offline signer. This includes the pubkey/signature pairs directly in the transaction rather than signing it with any local keypair(s)

### Example: Submitting an Offline Signed Payment <a href="#example-submitting-an-offline-signed-payment" id="example-submitting-an-offline-signed-payment"></a>

Command

```
put@online$ put transfer --blockhash 5Tx8F3jgSHx21CbtjwmdaKPLM5tWmreWAnPrbqHomSJF \
    --signer FhtzLVsmcV7S5XqGD79ErgoseCLhZYmEZnz9kQg1Rp7j=4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN
    recipient-keypair.json 1
```

Output

```
4vC38p4bz7XyiXrk6HtaooUqwxTWKocf45cstASGtmrD398biNJnmTcUCVEojE7wVQvgdYbjHJqRFZPpzfCQpmUN
```

## Offline Signing Over Multiple Sessions <a href="#offline-signing-over-multiple-sessions" id="offline-signing-over-multiple-sessions"></a>

Offline signing can also take place over multiple sessions. In this scenario, pass the absent signer's public key for each role.&#x20;

All pubkeys that were specified, but no signature was generated for will be listed as absent in the offline signing output

### Example: Transfer with Two Offline Signing Sessions <a href="#example-transfer-with-two-offline-signing-sessions" id="example-transfer-with-two-offline-signing-sessions"></a>

Command (Offline Session #1)

```
put@offline1$ put transfer Fdri24WUGtrCXZ55nXiewAj6RM18hRHPGAjZk3o6vBut 10 \
--blockhash 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc \
--sign-only \
--keypair fee_payer.json \
--from 674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL
```

Output (Offline Session #1)

```
Blockhash: 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc
Signers (Pubkey=Signature):
    3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy=ohGKvpRC46jAduwU9NW8tP91JkCT5r8Mo67Ysnid4zc76tiiV1Ho6jv3BKFSbBcr2NcPPCarmfTLSkTHsJCtdYi
  Absent Signers (Pubkey):
    674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL
```

Command (Offline Session #2)

```
put@offline2$ put transfer Fdri24WUGtrCXZ55nXiewAj6RM18hRHPGAjZk3o6vBut 10 \
  --blockhash 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc \
  --sign-only \
  --keypair from.json \
  --fee-payer 3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy
```

Output (Offline Session #2)

```
Blockhash: 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc
Signers (Pubkey=Signature):
  674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL=3vJtnba4dKQmEAieAekC1rJnPUndBcpvqRPRMoPWqhLEMCty2SdUxt2yvC1wQW6wVUa5putZMt6kdwCaTv8gk7sQ
Absent Signers (Pubkey):3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy
```

Command (Online Submission)

```
put@online$ put transfer Fdri24WUGtrCXZ55nXiewAj6RM18hRHPGAjZk3o6vBut 10 \
  --blockhash 7ALDjLv56a8f6sH6upAZALQKkXyjAwwENH9GomyM8Dbc \
  --from 674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL \
  --signer 674RgFMgdqdRoVtMqSBg7mHFbrrNm1h1r721H1ZMquHL=3vJtnba4dKQmEAieAekC1rJnPUndBcpvqRPRMoPWqhLEMCty2SdUxt2yvC1wQW6wVUa5putZMt6kdwCaTv8gk7sQ \
  --fee-payer 3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy \
  --signer 3bo5YiRagwmRikuH6H1d2gkKef5nFZXE3gJeoHxJbPjy=ohGKvpRC46jAduwU9NW8tP91JkCT5r8Mo67Ysnid4zc76tiiV1Ho6jv3BKFSbBcr2NcPPCarmfTLSkTHsJCtdYi
```

Output (Online Submission)

```
ohGKvpRC46jAduwU9NW8tP91JkCT5r8Mo67Ysnid4zc76tiiV1Ho6jv3BKFSbBcr2NcPPCarmfTLSkTHsJCtdYi
```

## Buying More Time to Sign <a href="#buying-more-time-to-sign" id="buying-more-time-to-sign"></a>

Typically a PUT transaction must be signed and accepted by the network within a number of slots from the blockhash in its `recent_blockhash` field (\~1min at the time of this writing). If your signing procedure takes longer than this, a Durable Transaction Nonce can give you the extra time you need.


# Durable Transaction Nonces

## Durable Transaction Nonces

Durable transaction nonces are a mechanism for getting around the typical short lifetime of a transaction's recent\_blockhash.&#x20;

They are implemented as a PUT Program, the mechanics of which can be read about in the proposal.

## Usage Examples

Full usage details for durable nonce CLI commands can be found in the CLI reference.

### Nonce Authority

Authority over a nonce account can optionally be assigned to another account.&#x20;

In doing so the new authority inherits full control over the nonce account from the previous authority, including the account creator.&#x20;

This feature enables the creation of more complex account ownership arrangements and derived account addresses not associated with a keypair.&#x20;

The --nonce-authority \<AUTHORITY\_KEYPAIR> argument is used to specify this account and is supported by the following commands

* `create-nonce-account`
* `new-nonce`
* `withdraw-from-nonce-account`
* `authorize-nonce-account`

### Nonce Account Creation

The durable transaction nonce feature uses an account to store the next nonce value. Durable nonce accounts must be rent-exempt, so need to carry the minimum balance to achieve this.

A nonce account is created by first generating a new keypair, then create the account on chain

Command

```
put-keygen new -o nonce-keypair.json
put create-nonce-account nonce-keypair.json 1
```

Output

```
2SymGjGV4ksPdpbaqWFiDoBz8okvtiik4KE9cnMQgRHrRLySSdZ6jrEcpPifW4xUpp4z66XM9d9wM48sA7peG2XL
```

To keep the keypair entirely offline, use the Paper Wallet keypair generation instructions instead

Full usage documentation

### Querying the Stored Nonce Value

Creating a durable nonce transaction requires passing the stored nonce value as the value to the --blockhash argument upon signing and submission.&#x20;

Obtain the presently stored nonce value with

Command

```
put nonce nonce-keypair.json
```

Output

```
8GRipryfxcsxN8mAGjy8zbFo9ezaUsh47TsPzmZbuytU
```

Full usage documentation

### Advancing the Stored Nonce Value

While not typically needed outside a more useful transaction, the stored nonce value can be advanced by

Command

```
put new-nonce nonce-keypair.json
```

Output

```
44jYe1yPKrjuYDmoFTdgPjg8LFpYyh1PFKJqm5SC1PiSyAL8iw1bhadcAX1SL7KDmREEkmHpYvreKoNv6fZgfvUK
```

### Display Nonce Account

Inspect a nonce account in a more human friendly format with

* Command

```
put nonce-account nonce-keypair.json
```

* Output

```
balance: 0.5 PUT
minimum balance required: 0.00136416 PUT
nonce: DZar6t2EaCFQTbUP4DHKwZ1wT8gCPW2aRfkVWhydkBvS
```

> Full usage documentation

### Withdraw Funds from a Nonce Account <a href="#withdraw-funds-from-a-nonce-account" id="withdraw-funds-from-a-nonce-account"></a>

Withdraw funds from a nonce account with

* Command

```
put withdraw-from-nonce-account nonce-keypair.json ~/.config/put/id.json 
0.5
```

* Output

```
3foNy1SBqwXSsfSfTdmYKDuhnVheRnKXpoPySiUDBVeDEs6iMVokgqm7AqfTjbk7QBE8mqomvMUMNQhtdMvFLide
```

> Close a nonce account by withdrawing the full balance

> Full usage documentation

### Assign a New Authority to a Nonce Account <a href="#assign-a-new-authority-to-a-nonce-account" id="assign-a-new-authority-to-a-nonce-account"></a>

Reassign the authority of a nonce account after creation with

* Command

```
put authorize-nonce-account nonce-keypair.json nonce-authority.json
```

* Output

```
3F9cg4zN9wHxLGx4c3cUKmqpej4oa67QbALmChsJbfxTgTffRiL3iUehVhR9wQmWgPua66jPuAYeL1K2pYYjbNoT
```

> Full usage documentation

## Other Commands Supporting Durable Nonces <a href="#other-commands-supporting-durable-nonces" id="other-commands-supporting-durable-nonces"></a>

To make use of durable nonces with other CLI subcommands, two arguments must be supported.

* `--nonce`, specifies the account storing the nonce value
* `--nonce-authority`, specifies an optional nonce authority

The following subcommands have received this treatment so far

* `pay`
* `delegate-stake`
* `deactivate-stake`

### Example Pay Using Durable Nonce <a href="#example-pay-using-durable-nonce" id="example-pay-using-durable-nonce"></a>

Here we demonstrate Alice paying Bob 1 SOL using a durable nonce. The procedure is the same for all subcommands supporting durable nonces

**- Create accounts**[**#**](https://docs.solana.com/offline-signing/durable-nonce#--create-accounts)

First we need some accounts for Alice, Alice's nonce and Bob

```
$ put-keygen new -o alice.json
$ put-keygen new -o nonce.json
$ put-keygen new -o bob.json
```

* Fund Alice's account#

Alice will need some funds to create a nonce account and send to Bob. Airdrop her some PUT

```
$ put airdrop -k alice.json 1
1 PUT
```

* Create Alice's nonce account#

Now Alice needs a nonce account. Create one

```
Here, no separate nonce authority is employed, so alice.json has full authority over the nonce account
```

$ put create-nonce-account -k alice.json nonce.json 0.1 3KPZr96BTsL3hqera9up82KAU462Gz31xjqJ6eHUAjF935Yf8i1kmfEbo6SVbNaACKE5z6gySrNjVRvmS8DcPuwV

* A failed first attempt to pay Bob#

Alice attempts to pay Bob, but takes too long to sign. The specified blockhash expires and the transaction fails

```
$ put transfer -k alice.json --blockhash expiredDTaxfagttWjQweib42b6ZHADSx94Tw8gHx11 bob.json 0.01
[2020-01-02T18:48:28.462911000Z ERROR put_cli::cli] Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" })
Error: Io(Custom { kind: Other, error: "Transaction \"33gQQaoPc9jWePMvDAeyJpcnSPiGUAdtVg8zREWv4GiKjkcGNufgpcbFyRKRrA25NkgjZySEeKue5rawyeH5TzsV\" failed: None" })
```

* Nonce to the rescue!#

Alice retries the transaction, this time specifying her nonce account and the blockhash stored there

Remember, alice.json is the nonce authority in this example

```
$ put nonce-account nonce.json
balance: 0.1 PUT
minimum balance required: 0.00136416 PUT
nonce: F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7

$ put transfer -k alice.json --blockhash F7vmkY3DTaxfagttWjQweib42b6ZHADSx94Tw8gHx3W7 --nonce nonce.json bob.json 0.01
HR1368UKHVZyenmH7yVz5sBAijV6XAPeWbEiXEGVYQorRMcoijeNAbzZqEZiH8cDB8tk65ckqeegFjK8dHwNFgQ
```

* Success!#

The transaction succeeds! Bob receives 0.01 PUT from Alice and Alice's stored nonce advances to a new value

```
$ put balance -k bob.json
0.01 PUT


$ put nonce-account nonce.json
balance: 0.1 PUT
minimum balance required: 0.00136416 PUT
nonce: 6bjroqDcZgTv6Vavhqf81oBHTv3aMnX19UTB51YhAZnN
```


# CLI Usage Reference

The PUT-CLI crate provides a command-line interface tool for Solana

## Examples

### Get Pubkey <a href="#get-pubkey" id="get-pubkey"></a>

```
// Command
$ put-keygen pubkey

// Return
<PUBKEY>

```

### Airdrop PUT/Lamports

```
// Command
$ put airdrop 1

// Return
"1 PUT"

```

### Get Balance

```
// Command
$ put balance

// Return
"3.00050001 PUT"

```

### Confirm Transaction

```
// Command
$ put confirm <TX_SIGNATURE>

// Return
"Confirmed" / "Not found" / "Transaction failed with error <ERR>"

```

### Deploy program

```
// Command
$ put program deploy <PATH>

// Return
<PROGRAM_ID>

```

## Usage

### PUT-CLI

```
put-cli 1.14.7 (src:030eb5f2; feat:1443040149)
Blockchain, Rebuilt for Scale

USAGE:
    put [FLAGS] [OPTIONS] <SUBCOMMAND>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

SUBCOMMANDS:
    account                              Show the contents of an account
    address                              Get your public key
    address-lookup-table                 Address lookup table management
    airdrop                              Request PUT from a faucet
    authorize-nonce-account              Assign account authority to a new entity
    balance                              Get your balance
    block                                Get a confirmed block
    block-height                         Get current block height
    block-production                     Show information about block production
    block-time                           Get estimated production time of a block
    catchup                              Wait for a validator to catch up to the cluster
    close-vote-account                   Close a vote account and withdraw all funds remaining
    cluster-date                         Get current cluster date, computed from genesis creation time and network
                                         time
    cluster-version                      Get the version of the cluster entrypoint
    completion                           Generate completion scripts for various shells
    config                               Solana command-line tool configuration settings
    confirm                              Confirm transaction by signature
    create-address-with-seed             Generate a derived account address with a seed
    create-nonce-account                 Create a nonce account
    create-stake-account                 Create a stake account
    create-stake-account-checked         Create a stake account, checking the withdraw authority as a signer
    create-vote-account                  Create a vote account
    deactivate-stake                     Deactivate the delegated stake from the stake account
    decode-transaction                   Decode a serialized transaction
    delegate-stake                       Delegate stake to a vote account
    epoch                                Get current epoch
    epoch-info                           Get information about the current epoch
    feature                              Runtime feature management
    fees                                 Display current cluster fees (Deprecated in v1.8.0)
    first-available-block                Get the first available block in the storage
    genesis-hash                         Get the genesis hash
    gossip                               Show the current gossip network nodes
    help                                 Prints this message or the help of the given subcommand(s)
    inflation                            Show inflation information
    largest-accounts                     Get addresses of largest cluster accounts
    leader-schedule                      Display leader schedule
    live-slots                           Show information about the current slot progression
    logs                                 Stream transaction logs
    merge-stake                          Merges one stake account into another
    new-nonce                            Generate a new nonce, rendering the existing nonce useless
    nonce                                Get the current nonce value
    nonce-account                        Show the contents of a nonce account
    ping                                 Submit transactions sequentially
    program                              Program management
    redelegate-stake                     Redelegate active stake to another vote account
    rent                                 Calculate per-epoch and rent-exempt-minimum values for a given account data
                                         field length.
    resolve-signer                       Checks that a signer is valid, and returns its specific path; useful for
                                         signers that may be specified generally, eg. usb://ledger
    slot                                 Get current slot
    split-stake                          Duplicate a stake account, splitting the tokens between the two
    stake-account                        Show the contents of a stake account
    stake-authorize                      Authorize a new signing keypair for the given stake account
    stake-authorize-checked              Authorize a new signing keypair for the given stake account, checking the
                                         authority as a signer
    stake-history                        Show the stake history
    stake-minimum-delegation             Get the stake minimum delegation amount
    stake-set-lockup                     Set Lockup for the stake account
    stake-set-lockup-checked             Set Lockup for the stake account, checking the new authority as a signer
    stakes                               Show stake account information
    supply                               Get information about the cluster supply of PUT
    transaction-count                    Get current transaction count
    transaction-history                  Show historical transactions affecting the given address from newest to
                                         oldest
    transfer                             Transfer funds between system accounts
    upgrade-nonce-account                One-time idempotent upgrade of legacy nonce versions in order to bump them
                                         out of chain blockhash domain.
    validator-info                       Publish/get Validator info on Solana
    validators                           Show summary information about the current validators
    vote-account                         Show the contents of a vote account
    vote-authorize-voter                 Authorize a new vote signing keypair for the given vote account
    vote-authorize-voter-checked         Authorize a new vote signing keypair for the given vote account, checking
                                         the new authority as a signer
    vote-authorize-withdrawer            Authorize a new withdraw signing keypair for the given vote account
    vote-authorize-withdrawer-checked    Authorize a new withdraw signing keypair for the given vote account,
                                         checking the new authority as a signer
    vote-update-commission               Update the vote account's commission
    vote-update-validator                Update the vote account's validator identity
    wait-for-max-stake                   Wait for the max stake of any one node to drop below a percentage of total.
    withdraw-from-nonce-account          Withdraw PUT from the nonce account
    withdraw-from-vote-account           Withdraw lamports from a vote account into a specified account
    withdraw-stake                       Withdraw the unstaked PUT from the stake account

```

### put-account

```
put-account
Show the contents of an account

USAGE:
    put account [FLAGS] [OPTIONS] <ACCOUNT_ADDRESS>

FLAGS:
    -h, --help                           Prints help information
        --lamports                       Display balance in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
    -o, --output-file <FILEPATH>           Write the account data to this file
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <ACCOUNT_ADDRESS>    Account key URI. , one of:
                           * a base58-encoded public key
                           * a path to a keypair file
                           * a hyphen; signals a JSON-encoded keypair on stdin
                           * the 'ASK' keyword; to recover a keypair via its seed phrase
                           * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-address

```
put-address
Get your public key

USAGE:
    put address [FLAGS] [OPTIONS]

FLAGS:
        --confirm-key                    Confirm key on device; only relevant if using remote wallet
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-address-lookup-table

```
put-address-lookup-table
Address lookup table management

USAGE:
    put address-lookup-table [FLAGS] [OPTIONS] <SUBCOMMAND>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

SUBCOMMANDS:
    close         Permanently closes a lookup table
    create        Create a lookup table
    deactivate    Permanently deactivates a lookup table
    extend        Append more addresses to a lookup table
    freeze        Permanently freezes a lookup table
    get           Display information about a lookup table
    help          Prints this message or the help of the given subcommand(s)

```

### put-airdrop

```
put-airdrop
Request PUT from a faucet

USAGE:
    put airdrop [FLAGS] [OPTIONS] <AMOUNT> [RECIPIENT_ADDRESS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <AMOUNT>               The airdrop amount to request, in PUT
    <RECIPIENT_ADDRESS>    The account address of airdrop recipient. , one of:
                             * a base58-encoded public key
                             * a path to a keypair file
                             * a hyphen; signals a JSON-encoded keypair on stdin
                             * the 'ASK' keyword; to recover a keypair via its seed phrase
                             * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-authorize-nonce-account

```
put-authorize-nonce-account
Assign account authority to a new entity

USAGE:
    put authorize-nonce-account [FLAGS] [OPTIONS] <NONCE_ACCOUNT_ADDRESS> <AUTHORITY_PUBKEY>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <NONCE_ACCOUNT_ADDRESS>    Address of the nonce account. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)
    <AUTHORITY_PUBKEY>         Account to be granted authority of the nonce account. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-balance

```
put-balance
Get your balance

USAGE:
    put balance [FLAGS] [OPTIONS] [ACCOUNT_ADDRESS]

FLAGS:
    -h, --help                           Prints help information
        --lamports                       Display balance in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <ACCOUNT_ADDRESS>    The account address of the balance to check. , one of:
                           * a base58-encoded public key
                           * a path to a keypair file
                           * a hyphen; signals a JSON-encoded keypair on stdin
                           * the 'ASK' keyword; to recover a keypair via its seed phrase
                           * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-block

```
put-block
Get a confirmed block

USAGE:
    put block [FLAGS] [OPTIONS] [SLOT]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <SLOT>

```

### put-block-height

```
put-block-height
Get current block height

USAGE:
    put block-height [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-block-production

```
put-block-production
Show information about block production

USAGE:
    put block-production [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
        --epoch <epoch>                    Epoch to show block production for [default: current epoch]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --slot-limit <slot_limit>          Limit results to this many slots from the end of the epoch [default: full
                                           epoch]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-block-time

```
put-block-time
Get estimated production time of a block

USAGE:
    put block-time [FLAGS] [OPTIONS] [SLOT]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <SLOT>    Slot number of the block to query

```

### put-catchup

```
put-catchup
Wait for a validator to catch up to the cluster

USAGE:
    put catchup [FLAGS] [OPTIONS] [ARGS]

FLAGS:
        --follow                         Continue reporting progress even after the validator has caught up
    -h, --help                           Prints help information
        --log                            Don't update the progress inplace; instead show updates with its own new lines
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --our-localhost <PORT>             Guess Identity pubkey and validator rpc node assuming local (possibly
                                           private) validator [default: 8899]
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <OUR_VALIDATOR_PUBKEY>    Identity pubkey of the validator, one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)
    <OUR_URL>                 JSON RPC URL for validator, which is useful for validators with a private RPC service

```

### put-close-vote-account

```
put-close-vote-account
Close a vote account and withdraw all funds remaining

USAGE:
    put close-vote-account [FLAGS] [OPTIONS] <VOTE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --authorized-withdrawer <AUTHORIZED_KEYPAIR>      Authorized withdrawer [default: cli config keypair]
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <VOTE_ACCOUNT_ADDRESS>    Vote account to be closed. , one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)
    <RECIPIENT_ADDRESS>       The recipient of all withdrawn PUT. , one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-cluster-date

```
put-cluster-date
Get current cluster date, computed from genesis creation time and network time

USAGE:
    put cluster-date [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-cluster-version

```
put-cluster-version
Get the version of the cluster entrypoint

USAGE:
    put cluster-version [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-completion

```
put-completion
Generate completion scripts for various shells

USAGE:
    put completion [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
    -s, --shell <shell>                     [default: bash]  [possible values: bash, fish, zsh, powershell, elvish]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-config

```
put-config
Solana command-line tool configuration settings

USAGE:
    put config [FLAGS] [OPTIONS] <SUBCOMMAND>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

SUBCOMMANDS:
    export-address-labels    Export the current address labels
    get                      Get current config settings
    help                     Prints this message or the help of the given subcommand(s)
    import-address-labels    Import a list of address labels
    set                      Set a config setting

```

### put-confirm

```
put-confirm
Confirm transaction by signature

USAGE:
    put confirm [FLAGS] [OPTIONS] <TRANSACTION_SIGNATURE>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <TRANSACTION_SIGNATURE>    The transaction signature to confirm

Note: This will show more detailed information for finalized transactions with verbose mode (-v/--verbose).

Account modes:
  |srwx|
    s: signed
    r: readable (always true)
    w: writable
    x: program account (inner instructions excluded)

```

### put-create-address-with-seed

```
put-create-address-with-seed
Generate a derived account address with a seed

USAGE:
    put create-address-with-seed [FLAGS] [OPTIONS] <SEED_STRING> <PROGRAM_ID>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
        --from <FROM_PUBKEY>               From (base) key, [default: cli config keypair]. , one of:
                                             * a base58-encoded public key
                                             * a path to a keypair file
                                             * a hyphen; signals a JSON-encoded keypair on stdin
                                             * the 'ASK' keyword; to recover a keypair via its seed phrase
                                             * a hardware wallet keypair URL (i.e. usb://ledger)
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <SEED_STRING>    The seed.  Must not take more than 32 bytes to encode as utf-8
    <PROGRAM_ID>     The program_id that the address will ultimately be used for,
                     or one of NONCE, STAKE, and VOTE keywords

```

### put-create-nonce-account

```
put-create-nonce-account
Create a nonce account

USAGE:
    put create-nonce-account [FLAGS] [OPTIONS] <ACCOUNT_KEYPAIR> <AMOUNT>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce-authority <PUBKEY>
            Assign noncing authority to another entity. , one of:
              * a base58-encoded public key
              * a path to a keypair file
              * a hyphen; signals a JSON-encoded keypair on stdin
              * the 'ASK' keyword; to recover a keypair via its seed phrase
              * a hardware wallet keypair URL (i.e. usb://ledger)
        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --seed <STRING>
            Seed for address generation; if specified, the resulting account will be at a derived address of the
            NONCE_ACCOUNT pubkey
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <ACCOUNT_KEYPAIR>    Keypair of the nonce account to fund
    <AMOUNT>             The amount to load the nonce account with, in PUT; accepts keyword ALL

```

### put-create-stake-account

```
put-create-stake-account
Create a stake account

USAGE:
    put create-stake-account [FLAGS] [OPTIONS] <STAKE_ACCOUNT_KEYPAIR> <AMOUNT>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --custodian <PUBKEY>
            Authority to modify lockups. , one of:
              * a base58-encoded public key
              * a path to a keypair file
              * a hyphen; signals a JSON-encoded keypair on stdin
              * the 'ASK' keyword; to recover a keypair via its seed phrase
              * a hardware wallet keypair URL (i.e. usb://ledger)
        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
        --from <KEYPAIR>                                  Source account of funds [default: cli config keypair]
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --lockup-date <RFC3339 DATETIME>
            The date and time at which this account will be available for withdrawal

        --lockup-epoch <NUMBER>
            The epoch height at which this account will be available for withdrawal

        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --seed <STRING>
            Seed for address generation; if specified, the resulting account will be at a derived address of the
            STAKE_ACCOUNT_KEYPAIR pubkey
        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --stake-authority <PUBKEY>                        Authorized staker [default: cli config keypair]
        --ws <URL>                                        WebSocket URL for the put cluster
        --withdraw-authority <PUBKEY>                     Authorized withdrawer [default: cli config keypair]

ARGS:
    <STAKE_ACCOUNT_KEYPAIR>    Stake account to create (or base of derived address if --seed is used)
    <AMOUNT>                   The amount to send to the stake account, in PUT; accepts keyword ALL

```

### put-create-stake-account-checked

```
put-create-stake-account-checked
Create a stake account, checking the withdraw authority as a signer

USAGE:
    put create-stake-account-checked [FLAGS] [OPTIONS] <STAKE_ACCOUNT_KEYPAIR> <AMOUNT>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
        --from <KEYPAIR>                                  Source account of funds [default: cli config keypair]
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --seed <STRING>
            Seed for address generation; if specified, the resulting account will be at a derived address of the
            STAKE_ACCOUNT_KEYPAIR pubkey
        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --stake-authority <PUBKEY>                        Authorized staker [default: cli config keypair]
        --ws <URL>                                        WebSocket URL for the put cluster
        --withdraw-authority <KEYPAIR>                    Authorized withdrawer [default: cli config keypair]

ARGS:
    <STAKE_ACCOUNT_KEYPAIR>    Stake account to create (or base of derived address if --seed is used)
    <AMOUNT>                   The amount to send to the stake account, in PUT; accepts keyword ALL

```

### put-create-vote-account

```
put-create-vote-account
Create a vote account

USAGE:
    put create-vote-account [FLAGS] [OPTIONS] <ACCOUNT_KEYPAIR> <IDENTITY_KEYPAIR> <WITHDRAWER_PUBKEY>

FLAGS:
        --allow-unsafe-authorized-withdrawer    Allow an authorized withdrawer pubkey to be identical to the validator
                                                identity account pubkey or vote account pubkey, which is normally an
                                                unsafe configuration and should be avoided.
        --dump-transaction-message              Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                                  Prints help information
        --no-address-labels                     Do not use address labels in the output
        --sign-only                             Sign the transaction offline
        --skip-seed-phrase-validation           Skip validation of seed phrases. Use this if your phrase does not use
                                                the BIP39 official English word list
    -V, --version                               Prints version information
    -v, --verbose                               Show additional information

OPTIONS:
        --authorized-voter <VOTER_PUBKEY>
            Public key of the authorized voter [default: validator identity pubkey]. , one of:
              * a base58-encoded public key
              * a path to a keypair file
              * a hyphen; signals a JSON-encoded keypair on stdin
              * the 'ASK' keyword; to recover a keypair via its seed phrase
              * a hardware wallet keypair URL (i.e. usb://ledger)
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commission <PERCENTAGE>
            The commission taken on reward redemption (0-100) [default: 100]

        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --seed <STRING>
            Seed for address generation; if specified, the resulting account will be at a derived address of the VOTE
            ACCOUNT pubkey
        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <ACCOUNT_KEYPAIR>      Vote account keypair to create
    <IDENTITY_KEYPAIR>     Keypair of validator that will vote with this account
    <WITHDRAWER_PUBKEY>    Public key of the authorized withdrawer, one of:
                             * a base58-encoded public key
                             * a path to a keypair file
                             * a hyphen; signals a JSON-encoded keypair on stdin
                             * the 'ASK' keyword; to recover a keypair via its seed phrase
                             * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-deactivate-stake

```
put-deactivate-stake
Deactivate the delegated stake from the stake account

USAGE:
    put deactivate-stake [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS>

FLAGS:
        --delinquent                     Deactivate abandoned stake that is currently delegated to a delinquent vote
                                         account
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --seed <STRING>
            Seed for address generation; if specified, the resulting account will be at a derived address of
            STAKE_ACCOUNT_ADDRESS
        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --stake-authority <KEYPAIR>                       Authorized staker [default: cli config keypair]
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <STAKE_ACCOUNT_ADDRESS>    Stake account to be deactivated (or base of derived address if --seed is used). , one
                               of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-decode-transaction

```
put-decode-transaction
Decode a serialized transaction

USAGE:
    put decode-transaction [FLAGS] [OPTIONS] <TRANSACTION> <ENCODING>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <TRANSACTION>    transaction to decode
    <ENCODING>       transaction encoding [default: base58]  [possible values: base58, base64]

```

### put-delegate-stake

```
put-delegate-stake
Delegate stake to a vote account

USAGE:
    put delegate-stake [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS> <VOTE_ACCOUNT_ADDRESS>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --stake-authority <KEYPAIR>                       Authorized staker [default: cli config keypair]
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <STAKE_ACCOUNT_ADDRESS>    Stake account to delegate, one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)
    <VOTE_ACCOUNT_ADDRESS>     The vote account to which the stake will be delegated, one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-epoch

```
put-epoch
Get current epoch

USAGE:
    put epoch [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-epoch-info

```
put-epoch-info
Get information about the current epoch

USAGE:
    put epoch-info [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-feature

```
put-feature
Runtime feature management

USAGE:
    put feature [FLAGS] [OPTIONS] <SUBCOMMAND>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

SUBCOMMANDS:
    activate    Activate a runtime feature
    help        Prints this message or the help of the given subcommand(s)
    status      Query runtime feature status

```

### put-fees

```
put-fees
Display current cluster fees (Deprecated in v1.8.0)

USAGE:
    put fees [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>            Query fees for BLOCKHASH instead of the the most recent blockhash
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-first-available-block

```
put-first-available-block
Get the first available block in the storage

USAGE:
    put first-available-block [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-genesis-hash

```
put-genesis-hash
Get the genesis hash

USAGE:
    put genesis-hash [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-gossip

```
put-gossip
Show the current gossip network nodes

USAGE:
    put gossip [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-help

```
put-help
Prints this message or the help of the given subcommand(s)

USAGE:
    put help [subcommand]...

ARGS:
    <subcommand>...    The subcommand whose help message to display
put-inflation#
put-inflation
Show inflation information

USAGE:
    put inflation [FLAGS] [OPTIONS] [SUBCOMMAND]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

SUBCOMMANDS:
    help       Prints this message or the help of the given subcommand(s)
    rewards    Show inflation rewards for a set of addresses

```

### put-largest-accounts

```
put-largest-accounts
Get addresses of largest cluster accounts

USAGE:
    put largest-accounts [FLAGS] [OPTIONS]

FLAGS:
        --circulating                    Filter address list to only circulating accounts
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --non-circulating                Filter address list to only non-circulating accounts
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-leader-schedule

```
put-leader-schedule
Display leader schedule

USAGE:
    put leader-schedule [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
        --epoch <EPOCH>                    Epoch to show leader schedule for. [default: current]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-live-slots

```
put-live-slots
Show information about the current slot progression

USAGE:
    put live-slots [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-logs

```
put-logs
Stream transaction logs

USAGE:
    put logs [FLAGS] [OPTIONS] [ADDRESS]

FLAGS:
    -h, --help                           Prints help information
        --include-votes                  Include vote transactions when monitoring all transactions
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <ADDRESS>    Account address to monitor [default: monitor all transactions except for votes] , one of:
                   * a base58-encoded public key
                   * a path to a keypair file
                   * a hyphen; signals a JSON-encoded keypair on stdin
                   * the 'ASK' keyword; to recover a keypair via its seed phrase
                   * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-merge-stake

```
put-merge-stake
Merges one stake account into another

USAGE:
    put merge-stake [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS> <SOURCE_STAKE_ACCOUNT_ADDRESS>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --stake-authority <KEYPAIR>                       Authorized staker [default: cli config keypair]
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <STAKE_ACCOUNT_ADDRESS>           Stake account to merge into, one of:
                                        * a base58-encoded public key
                                        * a path to a keypair file
                                        * a hyphen; signals a JSON-encoded keypair on stdin
                                        * the 'ASK' keyword; to recover a keypair via its seed phrase
                                        * a hardware wallet keypair URL (i.e. usb://ledger)
    <SOURCE_STAKE_ACCOUNT_ADDRESS>    Source stake account for the merge.  If successful, this stake account will no
                                      longer exist after the merge, one of:
                                        * a base58-encoded public key
                                        * a path to a keypair file
                                        * a hyphen; signals a JSON-encoded keypair on stdin
                                        * the 'ASK' keyword; to recover a keypair via its seed phrase
                                        * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-new-nonce

```
put-new-nonce
Generate a new nonce, rendering the existing nonce useless

USAGE:
    put new-nonce [FLAGS] [OPTIONS] <NONCE_ACCOUNT_ADDRESS>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <NONCE_ACCOUNT_ADDRESS>    Address of the nonce account. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-nonce

```
put-nonce
Get the current nonce value

USAGE:
    put nonce [FLAGS] [OPTIONS] <NONCE_ACCOUNT_ADDRESS>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <NONCE_ACCOUNT_ADDRESS>    Address of the nonce account to display. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-nonce-account

```
put-nonce-account
Show the contents of a nonce account

USAGE:
    put nonce-account [FLAGS] [OPTIONS] <NONCE_ACCOUNT_ADDRESS>

FLAGS:
    -h, --help                           Prints help information
        --lamports                       Display balance in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <NONCE_ACCOUNT_ADDRESS>    Address of the nonce account to display. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-ping

```
put-ping
Submit transactions sequentially

USAGE:
    put ping [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
    -D, --print-timestamp                Print timestamp (unix time + microseconds as in gettimeofday) before each line
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

    -c, --count <NUMBER>                                  Stop after submitting count transactions
    -i, --interval <SECONDS>
            Wait interval seconds between submitting the next transaction [default: 2]

    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

    -t, --timeout <SECONDS>
            Wait up to timeout seconds for transaction confirmation [default: 15]

        --ws <URL>                                        WebSocket URL for the put cluster

```

### put-program

```
put-program
Program management

USAGE:
    put program [FLAGS] [OPTIONS] <SUBCOMMAND>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

SUBCOMMANDS:
    close                    Close a program or buffer account and withdraw all lamports
    deploy                   Deploy an upgradeable program
    dump                     Write the program data to a file
    help                     Prints this message or the help of the given subcommand(s)
    set-buffer-authority     Set a new buffer authority
    set-upgrade-authority    Set a new program authority
    show                     Display information about a buffer or program
    write-buffer             Writes a program into a buffer account

```

### put-redelegate-stake

```
put-redelegate-stake
Redelegate active stake to another vote account

USAGE:
    put redelegate-stake [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS> <REDELEGATED_VOTE_ACCOUNT_ADDRESS> <REDELEGATION_STAKE_ACCOUNT>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>            Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
        --fee-payer <KEYPAIR>              Specify the fee-payer account. This may be a keypair file, the ASK keyword
                                           or the pubkey of an offline signer, provided an appropriate --signer argument
                                           is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --with-memo <MEMO>                 Specify a memo string to include in the transaction.
        --nonce <PUBKEY>                   Provide the nonce account to use when creating a nonced
                                           transaction. Nonced transactions are useful when a transaction
                                           requires a lengthy signing process. Learn more about nonced
                                           transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>        Provide the nonce authority keypair to use when signing a nonced transaction
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --signer <PUBKEY=SIGNATURE>...     Provide a public-key/signature pair for the transaction
        --stake-authority <KEYPAIR>        Authorized staker [default: cli config keypair]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <STAKE_ACCOUNT_ADDRESS>               Existing delegated stake account that has been fully activated. On success
                                          this stake account will be scheduled for deactivation and the rent-exempt
                                          balance may be withdrawn once fully deactivated, one of:
                                            * a base58-encoded public key
                                            * a path to a keypair file
                                            * a hyphen; signals a JSON-encoded keypair on stdin
                                            * the 'ASK' keyword; to recover a keypair via its seed phrase
                                            * a hardware wallet keypair URL (i.e. usb://ledger)
    <REDELEGATED_VOTE_ACCOUNT_ADDRESS>    The vote account to which the stake will be redelegated, one of:
                                            * a base58-encoded public key
                                            * a path to a keypair file
                                            * a hyphen; signals a JSON-encoded keypair on stdin
                                            * the 'ASK' keyword; to recover a keypair via its seed phrase
                                            * a hardware wallet keypair URL (i.e. usb://ledger)
    <REDELEGATION_STAKE_ACCOUNT>          Stake account to create for the redelegation. On success this stake
                                          account will be created and scheduled for activation with all the stake in
                                          the existing stake account, exclusive of the rent-exempt balance retained
                                          in the existing account

```

### put-rent

```
put-rent
Calculate per-epoch and rent-exempt-minimum values for a given account data field length.

USAGE:
    put rent [FLAGS] [OPTIONS] <DATA_LENGTH_OR_MONIKER>

FLAGS:
    -h, --help                           Prints help information
        --lamports                       Display rent in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <DATA_LENGTH_OR_MONIKER>    Length of data field in the account to calculate rent for, or moniker: [nonce,
                                stake, system, vote]

```

### put-resolve-signer

```
put-resolve-signer
Checks that a signer is valid, and returns its specific path; useful for signers that may be specified generally, eg.
usb://ledger

USAGE:
    put resolve-signer [FLAGS] [OPTIONS] <SIGNER_KEYPAIR>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <SIGNER_KEYPAIR>    The signer path to resolve

```

### put-slot

```
put-slot
Get current slot

USAGE:
    put slot [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-split-stake

```
put-split-stake
Duplicate a stake account, splitting the tokens between the two

USAGE:
    put split-stake [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS> <SPLIT_STAKE_ACCOUNT> <AMOUNT>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --seed <STRING>
            Seed for address generation; if specified, the resulting account will be at a derived address of
            SPLIT_STAKE_ACCOUNT
        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --stake-authority <KEYPAIR>                       Authorized staker [default: cli config keypair]
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <STAKE_ACCOUNT_ADDRESS>    Stake account to split (or base of derived address if --seed is used). , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)
    <SPLIT_STAKE_ACCOUNT>      Keypair of the new stake account
    <AMOUNT>                   The amount to move into the new stake account, in PUT

```

### put-stake-account

```
put-stake-account
Show the contents of a stake account

USAGE:
    put stake-account [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS>

FLAGS:
    -h, --help                           Prints help information
        --lamports                       Display balance in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information
        --with-rewards                   Display inflation rewards

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --num-rewards-epochs <NUM>         Display rewards for NUM recent epochs, max 10 [default: latest epoch only]
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <STAKE_ACCOUNT_ADDRESS>    The stake account to display. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-stake-authorize

```
put-stake-authorize
Authorize a new signing keypair for the given stake account

USAGE:
    put stake-authorize [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS> --new-stake-authority <PUBKEY> --new-withdraw-authority <PUBKEY>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --no-wait                        Return signature immediately after submitting the transaction, instead of
                                         waiting for confirmations
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --custodian <KEYPAIR>                             Authority to override account lockup
        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --new-stake-authority <PUBKEY>
            New authorized staker, one of:
              * a base58-encoded public key
              * a path to a keypair file
              * a hyphen; signals a JSON-encoded keypair on stdin
              * the 'ASK' keyword; to recover a keypair via its seed phrase
              * a hardware wallet keypair URL (i.e. usb://ledger)
        --new-withdraw-authority <PUBKEY>
            New authorized withdrawer. , one of:
              * a base58-encoded public key
              * a path to a keypair file
              * a hyphen; signals a JSON-encoded keypair on stdin
              * the 'ASK' keyword; to recover a keypair via its seed phrase
              * a hardware wallet keypair URL (i.e. usb://ledger)
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --stake-authority <KEYPAIR>                       Authorized staker [default: cli config keypair]
        --ws <URL>                                        WebSocket URL for the put cluster
        --withdraw-authority <KEYPAIR>                    Authorized withdrawer [default: cli config keypair]

ARGS:
    <STAKE_ACCOUNT_ADDRESS>    Stake account in which to set a new authority. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-stake-authorize-checked

```
put-stake-authorize-checked
Authorize a new signing keypair for the given stake account, checking the authority as a signer

USAGE:
    put stake-authorize-checked [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --no-wait                        Return signature immediately after submitting the transaction, instead of
                                         waiting for confirmations
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --custodian <KEYPAIR>                             Authority to override account lockup
        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --new-stake-authority <KEYPAIR>                   New authorized staker
        --new-withdraw-authority <KEYPAIR>                New authorized withdrawer
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --stake-authority <KEYPAIR>                       Authorized staker [default: cli config keypair]
        --ws <URL>                                        WebSocket URL for the put cluster
        --withdraw-authority <KEYPAIR>                    Authorized withdrawer [default: cli config keypair]

ARGS:
    <STAKE_ACCOUNT_ADDRESS>    Stake account in which to set a new authority. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-stake-history

```
put-stake-history
Show the stake history

USAGE:
    put stake-history [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --lamports                       Display balance in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --limit <NUM>                      Display NUM recent epochs worth of stake history in text mode. 0 for all
                                           [default: 10]
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-stake-minimum-delegation

```
put-stake-minimum-delegation
Get the stake minimum delegation amount

USAGE:
    put stake-minimum-delegation [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --lamports                       Display minimum delegation in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

### put-stake-set-lockup

```
put-stake-set-lockup
Set Lockup for the stake account

USAGE:
    put stake-set-lockup [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS> <--lockup-epoch <NUMBER>|--lockup-date <RFC3339 DATETIME>|--new-custodian <PUBKEY>>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --custodian <KEYPAIR>                             Keypair of the existing custodian [default: cli config pubkey]
        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --lockup-date <RFC3339 DATETIME>
            The date and time at which this account will be available for withdrawal

        --lockup-epoch <NUMBER>
            The epoch height at which this account will be available for withdrawal

        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --new-custodian <PUBKEY>
            Identity of a new lockup custodian. , one of:
              * a base58-encoded public key
              * a path to a keypair file
              * a hyphen; signals a JSON-encoded keypair on stdin
              * the 'ASK' keyword; to recover a keypair via its seed phrase
              * a hardware wallet keypair URL (i.e. usb://ledger)
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <STAKE_ACCOUNT_ADDRESS>    Stake account for which to set lockup parameters. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-stake-set-lockup-checked

```
put-stake-set-lockup-checked
Set Lockup for the stake account, checking the new authority as a signer

USAGE:
    put stake-set-lockup-checked [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS> <--lockup-epoch <NUMBER>|--lockup-date <RFC3339 DATETIME>|--new-custodian <KEYPAIR>>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --custodian <KEYPAIR>                             Keypair of the existing custodian [default: cli config pubkey]
        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --lockup-date <RFC3339 DATETIME>
            The date and time at which this account will be available for withdrawal

        --lockup-epoch <NUMBER>
            The epoch height at which this account will be available for withdrawal

        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --new-custodian <KEYPAIR>                         Keypair of a new lockup custodian
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <STAKE_ACCOUNT_ADDRESS>    Stake account for which to set lockup parameters. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-stakes

```
put-stakes
Show stake account information

USAGE:
    put stakes [FLAGS] [OPTIONS] [VOTE_ACCOUNT_PUBKEYS]...

FLAGS:
    -h, --help                           Prints help information
        --lamports                       Display balance in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster
        --withdraw-authority <PUBKEY>      Only show stake accounts with the provided withdraw authority. , one of:
                                             * a base58-encoded public key
                                             * a path to a keypair file
                                             * a hyphen; signals a JSON-encoded keypair on stdin
                                             * the 'ASK' keyword; to recover a keypair via its seed phrase
                                             * a hardware wallet keypair URL (i.e. usb://ledger)

ARGS:
    <VOTE_ACCOUNT_PUBKEYS>...    Only show stake accounts delegated to the provided vote accounts. , one of:
                                   * a base58-encoded public key
                                   * a path to a keypair file
                                   * a hyphen; signals a JSON-encoded keypair on stdin
                                   * the 'ASK' keyword; to recover a keypair via its seed phrase
                                   * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-supply

```
put-supply
Get information about the cluster supply of PUT

USAGE:
    put supply [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --print-accounts                 Print list of non-circualting account addresses
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

put-transaction-count

```
put-transaction-count
Get current transaction count

USAGE:
    put transaction-count [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

```

put-transaction-history

```
put-transaction-history
Show historical transactions affecting the given address from newest to oldest

USAGE:
    put transaction-history [FLAGS] [OPTIONS] <ADDRESS>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --show-transactions              Display the full transactions
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --before <TRANSACTION_SIGNATURE>    Start with the first signature older than this one
        --commitment <COMMITMENT_LEVEL>     Return information at the selected commitment level [possible values:
                                            processed, confirmed, finalized]
    -C, --config <FILEPATH>                 Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>              URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                            testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                 Filepath or URL to a keypair
        --limit <LIMIT>                     Maximum number of transaction signatures to return [default: 1000]
        --output <FORMAT>                   Return information in specified output format [possible values: json, json-
                                            compact]
        --ws <URL>                          WebSocket URL for the put cluster

ARGS:
    <ADDRESS>    Account address, one of:
                   * a base58-encoded public key
                   * a path to a keypair file
                   * a hyphen; signals a JSON-encoded keypair on stdin
                   * the 'ASK' keyword; to recover a keypair via its seed phrase
                   * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-transfer

```
put-transfer
Transfer funds between system accounts

USAGE:
    put transfer [FLAGS] [OPTIONS] <RECIPIENT_ADDRESS> <AMOUNT>

FLAGS:
        --allow-unfunded-recipient       Complete the transfer even if the recipient address is not funded
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --no-wait                        Return signature immediately after submitting the transaction, instead of
                                         waiting for confirmations
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
        --from <FROM_ADDRESS>
            Source account of funds (if different from client local account). , one of:
              * a base58-encoded public key
              * a path to a keypair file
              * a hyphen; signals a JSON-encoded keypair on stdin
              * the 'ASK' keyword; to recover a keypair via its seed phrase
              * a hardware wallet keypair URL (i.e. usb://ledger)
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <RECIPIENT_ADDRESS>    The account address of recipient. , one of:
                             * a base58-encoded public key
                             * a path to a keypair file
                             * a hyphen; signals a JSON-encoded keypair on stdin
                             * the 'ASK' keyword; to recover a keypair via its seed phrase
                             * a hardware wallet keypair URL (i.e. usb://ledger)
    <AMOUNT>               The amount to send, in PUT; accepts keyword ALL

```

### put-upgrade-nonce-account

```
put-upgrade-nonce-account
One-time idempotent upgrade of legacy nonce versions in order to bump them out of chain blockhash domain.

USAGE:
    put upgrade-nonce-account [FLAGS] [OPTIONS] <NONCE_ACCOUNT_ADDRESS>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <NONCE_ACCOUNT_ADDRESS>    Nonce account to upgrade. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-validator-info

```
put-validator-info
Publish/get Validator info on Solana

USAGE:
    put validator-info [FLAGS] [OPTIONS] <SUBCOMMAND>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

SUBCOMMANDS:
    get        Get and parse Solana Validator info
    help       Prints this message or the help of the given subcommand(s)
    publish    Publish Validator info on Solana

```

### put-validators\#

```
put-validators
Show summary information about the current validators

USAGE:
    put validators [FLAGS] [OPTIONS]

FLAGS:
    -h, --help                           Prints help information
        --keep-unstaked-delinquents      Don't discard unstaked, delinquent validators
        --lamports                       Display balance in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
    -n, --number                         Number the validators
    -r, --reverse                        Reverse order while sorting
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --delinquent-slot-distance <SLOT_DISTANCE>
            Minimum slot distance from the tip to consider a validator delinquent. [default: 128]

    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                           Filepath or URL to a keypair
        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --sort <sort>
            Sort order (does not affect JSON output) [default: stake]  [possible values: delinquent, commission,
            credits, identity, last-vote, root, skip-rate, stake, version, vote-account]
        --ws <URL>                                    WebSocket URL for the put cluster

```

### put-vote-account

```
put-vote-account
Show the contents of a vote account

USAGE:
    put vote-account [FLAGS] [OPTIONS] <VOTE_ACCOUNT_ADDRESS>

FLAGS:
    -h, --help                           Prints help information
        --lamports                       Display balance in lamports instead of PUT
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information
        --with-rewards                   Display inflation rewards

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --num-rewards-epochs <NUM>         Display rewards for NUM recent epochs, max 10 [default: latest epoch only]
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <VOTE_ACCOUNT_ADDRESS>    Vote account pubkey. , one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-vote-authorize-voter

```
put-vote-authorize-voter
Authorize a new vote signing keypair for the given vote account

USAGE:
    put vote-authorize-voter [FLAGS] [OPTIONS] <VOTE_ACCOUNT_ADDRESS> <AUTHORIZED_KEYPAIR> <NEW_AUTHORIZED_PUBKEY>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <VOTE_ACCOUNT_ADDRESS>     Vote account in which to set the authorized voter. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)
    <AUTHORIZED_KEYPAIR>       Current authorized vote signer.
    <NEW_AUTHORIZED_PUBKEY>    New authorized vote signer. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-vote-authorize-voter-checked

```
put-vote-authorize-voter-checked
Authorize a new vote signing keypair for the given vote account, checking the new authority as a signer

USAGE:
    put vote-authorize-voter-checked [FLAGS] [OPTIONS] <VOTE_ACCOUNT_ADDRESS> <AUTHORIZED_KEYPAIR> <NEW_AUTHORIZED_KEYPAIR>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <VOTE_ACCOUNT_ADDRESS>      Vote account in which to set the authorized voter. , one of:
                                  * a base58-encoded public key
                                  * a path to a keypair file
                                  * a hyphen; signals a JSON-encoded keypair on stdin
                                  * the 'ASK' keyword; to recover a keypair via its seed phrase
                                  * a hardware wallet keypair URL (i.e. usb://ledger)
    <AUTHORIZED_KEYPAIR>        Current authorized vote signer.
    <NEW_AUTHORIZED_KEYPAIR>    New authorized vote signer.

```

### put-vote-authorize-withdrawer

```
put-vote-authorize-withdrawer
Authorize a new withdraw signing keypair for the given vote account

USAGE:
    put vote-authorize-withdrawer [FLAGS] [OPTIONS] <VOTE_ACCOUNT_ADDRESS> <AUTHORIZED_KEYPAIR> <AUTHORIZED_PUBKEY>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <VOTE_ACCOUNT_ADDRESS>    Vote account in which to set the authorized withdrawer. , one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)
    <AUTHORIZED_KEYPAIR>      Current authorized withdrawer.
    <AUTHORIZED_PUBKEY>       New authorized withdrawer. , one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)

```

### put-vote-authorize-withdrawer-checked

```
put-vote-authorize-withdrawer-checked
Authorize a new withdraw signing keypair for the given vote account, checking the new authority as a signer

USAGE:
    put vote-authorize-withdrawer-checked [FLAGS] [OPTIONS] <VOTE_ACCOUNT_ADDRESS> <AUTHORIZED_KEYPAIR> <NEW_AUTHORIZED_KEYPAIR>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <VOTE_ACCOUNT_ADDRESS>      Vote account in which to set the authorized withdrawer. , one of:
                                  * a base58-encoded public key
                                  * a path to a keypair file
                                  * a hyphen; signals a JSON-encoded keypair on stdin
                                  * the 'ASK' keyword; to recover a keypair via its seed phrase
                                  * a hardware wallet keypair URL (i.e. usb://ledger)
    <AUTHORIZED_KEYPAIR>        Current authorized withdrawer.
    <NEW_AUTHORIZED_KEYPAIR>    New authorized withdrawer.

```

### put-vote-update-commission

```
put-vote-update-commission
Update the vote account's commission

USAGE:
    put vote-update-commission [FLAGS] [OPTIONS] <VOTE_ACCOUNT_ADDRESS> <PERCENTAGE> <AUTHORIZED_KEYPAIR>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <VOTE_ACCOUNT_ADDRESS>    Vote account to update. , one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)
    <PERCENTAGE>              The new commission
    <AUTHORIZED_KEYPAIR>      Authorized withdrawer keypair

```

### put-vote-update-validator

```
put-vote-update-validator
Update the vote account's validator identity

USAGE:
    put vote-update-validator [FLAGS] [OPTIONS] <VOTE_ACCOUNT_ADDRESS> <IDENTITY_KEYPAIR> <AUTHORIZED_KEYPAIR>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <VOTE_ACCOUNT_ADDRESS>    Vote account to update. , one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)
    <IDENTITY_KEYPAIR>        Keypair of new validator that will vote with this account
    <AUTHORIZED_KEYPAIR>      Authorized withdrawer keypair

```

### put-wait-for-max-stake

```
put-wait-for-max-stake
Wait for the max stake of any one node to drop below a percentage of total.

USAGE:
    put wait-for-max-stake [FLAGS] [OPTIONS] [PERCENT]

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>    Return information at the selected commitment level [possible values:
                                           processed, confirmed, finalized]
    -C, --config <FILEPATH>                Configuration file to use [default: ~/.config/put/cli/config.yml]
    -u, --url <URL_OR_MONIKER>             URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta,
                                           testnet, devnet, localhost]
    -k, --keypair <KEYPAIR>                Filepath or URL to a keypair
        --output <FORMAT>                  Return information in specified output format [possible values: json, json-
                                           compact]
        --ws <URL>                         WebSocket URL for the put cluster

ARGS:
    <PERCENT>

```

### put-withdraw-from-nonce-account

```
put-withdraw-from-nonce-account
Withdraw PUT from the nonce account

USAGE:
    put withdraw-from-nonce-account [FLAGS] [OPTIONS] <NONCE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS> <AMOUNT>

FLAGS:
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <NONCE_ACCOUNT_ADDRESS>    Nonce account to withdraw from. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)
    <RECIPIENT_ADDRESS>        The account to which the PUT should be transferred. , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)
    <AMOUNT>                   The amount to withdraw from the nonce account, in PUT

```

### put-withdraw-from-vote-account

```
put-withdraw-from-vote-account
Withdraw lamports from a vote account into a specified account

USAGE:
    put withdraw-from-vote-account [FLAGS] [OPTIONS] <VOTE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS> <AMOUNT>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --authorized-withdrawer <AUTHORIZED_KEYPAIR>      Authorized withdrawer [default: cli config keypair]
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster

ARGS:
    <VOTE_ACCOUNT_ADDRESS>    Vote account from which to withdraw. , one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)
    <RECIPIENT_ADDRESS>       The recipient of withdrawn PUT. , one of:
                                * a base58-encoded public key
                                * a path to a keypair file
                                * a hyphen; signals a JSON-encoded keypair on stdin
                                * the 'ASK' keyword; to recover a keypair via its seed phrase
                                * a hardware wallet keypair URL (i.e. usb://ledger)
    <AMOUNT>                  The amount to withdraw, in PUT; accepts keyword ALL, which for this command means
                              account balance minus rent-exempt minimum

```

### put-withdraw-stake

```
put-withdraw-stake
Withdraw the unstaked PUT from the stake account

USAGE:
    put withdraw-stake [FLAGS] [OPTIONS] <STAKE_ACCOUNT_ADDRESS> <RECIPIENT_ADDRESS> <AMOUNT>

FLAGS:
        --dump-transaction-message       Display the base64 encoded binary transaction message in sign-only mode
    -h, --help                           Prints help information
        --no-address-labels              Do not use address labels in the output
        --sign-only                      Sign the transaction offline
        --skip-seed-phrase-validation    Skip validation of seed phrases. Use this if your phrase does not use the BIP39
                                         official English word list
    -V, --version                        Prints version information
    -v, --verbose                        Show additional information

OPTIONS:
        --blockhash <BLOCKHASH>                           Use the supplied blockhash
        --commitment <COMMITMENT_LEVEL>
            Return information at the selected commitment level [possible values: processed, confirmed, finalized]

        --with-compute-unit-price <COMPUTE-UNIT-PRICE>
            Set compute unit price for transaction, in increments of 0.000001 lamports per compute unit.

    -C, --config <FILEPATH>
            Configuration file to use [default: ~/.config/put/cli/config.yml]

        --custodian <KEYPAIR>                             Authority to override account lockup
        --fee-payer <KEYPAIR>
            Specify the fee-payer account. This may be a keypair file, the ASK keyword
            or the pubkey of an offline signer, provided an appropriate --signer argument
            is also passed. Defaults to the client keypair.
    -u, --url <URL_OR_MONIKER>
            URL for Solana's JSON RPC or moniker (or their first letter): [mainnet-beta, testnet, devnet, localhost]

    -k, --keypair <KEYPAIR>                               Filepath or URL to a keypair
        --with-memo <MEMO>                                Specify a memo string to include in the transaction.
        --nonce <PUBKEY>
            Provide the nonce account to use when creating a nonced
            transaction. Nonced transactions are useful when a transaction
            requires a lengthy signing process. Learn more about nonced
            transactions at https://docs.put.com/offline-signing/durable-nonce
        --nonce-authority <KEYPAIR>
            Provide the nonce authority keypair to use when signing a nonced transaction

        --output <FORMAT>
            Return information in specified output format [possible values: json, json-compact]

        --seed <STRING>
            Seed for address generation; if specified, the resulting account will be at a derived address of
            STAKE_ACCOUNT_ADDRESS
        --signer <PUBKEY=SIGNATURE>...                    Provide a public-key/signature pair for the transaction
        --ws <URL>                                        WebSocket URL for the put cluster
        --withdraw-authority <KEYPAIR>                    Authorized withdrawer [default: cli config keypair]

ARGS:
    <STAKE_ACCOUNT_ADDRESS>    Stake account from which to withdraw (or base of derived address if --seed is used).
                               , one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)
    <RECIPIENT_ADDRESS>        Recipient of withdrawn PUT, one of:
                                 * a base58-encoded public key
                                 * a path to a keypair file
                                 * a hyphen; signals a JSON-encoded keypair on stdin
                                 * the 'ASK' keyword; to recover a keypair via its seed phrase
                                 * a hardware wallet keypair URL (i.e. usb://ledger)
    <AMOUNT>                   The amount to withdraw from the stake account, in PUT; accepts keyword ALL
```


# Developers


# Get Started


# Hello World

## Hello World Quickstart Guide

For this "hello world" quickstart guide, we will use PUT Playground, a browser the based IDE, to develop and deploy our PUT program.&#x20;

To use it, you do NOT have to install any software on your computer.&#x20;

Simply open PUT Playground in your browser of choice, and you are ready to write and deploy PUT programs.&#x20;

## What you will learn

* How to get started with PUT Playground
* How to create a PUT wallet on Playground
* How to program a basic PUT program in Rust
* How to build and deploy a PUT Rust program
* How to interact with your on chain program using JavaScript

## Using PUT Playground

PUT Playground is browser based application that will let you write, build, and deploy on chain PUT programs.&#x20;

All from your browser. No installation needed.

It is a great developer resource for getting started with PUT development, especially on Windows.&#x20;

### Import our example project

In a new tab in your browser, open our example "Hello World" project on PUT Playground: <https://beta.solpg.io/6314a69688a7fca897ad7d1d>

Next, import the project into your local workspace by clicking the "Import" icon and naming your project hello\_world.

lib.rs

```
use put_program::{
    account_info::AccountInfo,
    entrypoint,
    entrypoint::ProgramResult,
    pubkey::Pubkey
    msg,
};

// declare and export the program's entrypoint
entrypoing!(process_instruction);

```

If you do not import the program into your PUT Playground, then you will not be able to make changes to the code. But you will still be able to build and deploy the code to a PUT cluster.

### Create a Playground wallet

Normally with local development, you will need to create a file system wallet for use with the PUT CLI. But with the PUT Playground, you only need to click a few buttons to create a browser based wallet.

> **Note**:Your Playground Wallet will be saved in your browser's local storage. Clearing your browser cache will remove your saved wallet. When creating a new wallet, you will have the option to save a local copy of your wallet's keypair file.

Click on the red status indicator button at the bottom left of the screen, (optionally) save your wallet's keypair file to your computer for backup, then click "Continue".

After your Playground Wallet is created, you will notice the bottom of the window now states your wallet's address, your PUT balance, and the PUT cluster you are connected to (Devnet is usually the default/recommended, but a "localhost" test validator is also acceptable).&#x20;

## Create a PUT program

The code for your Rust based PUT program will live in your src/lib.rs file. Inside src/lib.rs you will be able to import your Rust crates and define your logic. Open your src/lib.rs file within PUT Playground.

### Import the PUT\_program crate\#

At the top of lib.rs, we import the PUT-program crate and bring our needed items into the local namespace:

```
use put_program::{
    account_info::AccountInfo,
    entrypoint,
    entrypoint::ProgramResult,
    pubkey::Pubkey,
    msg,
};
```

### Write your program logic

Every PUT program must define an entrypoint that tells the PUT runtime where to start executing your on chain code. Your program's entrypoint should provide a public function named process\_instruction:

```
// declare and export the program's entrypoint
entrypoint!(process_instruction);

// program entrypoint's implementation
pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8]
) -> ProgramResult {
    // log a message to the blockchain
    msg!("Hello, world!");

    // gracefully exit the program
    Ok(())
}
```

Every on chain program should return the Ok result enum with a value of (). This tells the PUT runtime that your program executed successfully without errors.

Our program above will simply log a message of "Hello, world!" to the blockchain cluster, then gracefully exit with Ok(()).

### Build your program

On the left sidebar, select the "Build & Deploy" tab. Next, click the "Build" button.

If you look at the Playground's terminal, you should see your PUT program begin to compile. Once complete, you will see a success message.

```

| ^^^^^^^^ help: if this is intentional,prefix it with an underscore:'_program_id'
|
= note: '#[warn(unused_vriables)]' on by default

warning: unused variable: 'accounts'
--> /src/lib.rs:15:5

  |
15| accounts: &[AccountInfo],
  | ^^^^^^^^ help: if this is intentional,prefix it with an underscore:'_accounts'

warning: unused variable: 'instruction_data'
--> /src/lib.rs:16:5

  |
16| instruction_data: &[u8],
  | ^^^^^^^^^^^^^^^^ help: if this is intentional,prefix it with an underscore:'_instruction_data'


warning: 'putpg'(lib) generated 3 warnings
Build successful.Completed in 0.28s.

$[]

```

Note: You may receive warning when your program is compiled due to unused variables.

&#x20;Don't worry, these warning will not affect your build.&#x20;

They are due to our very simple program not using all the variables we declared in the process\_instruction function.

### Deploy your program

You can click the "Deploy" button to deploy your first program to the PUT blockchain. Specifically to your selected cluster (e.g. Devnet, Testnet, etc).

After each deployment, you will see your Playground Wallet balance change. By default, PUT Playground will automatically request PUT airdrops on your behalf to ensure your wallet has enough PUT to cover the cost of deployment.

> Note: If you need more PUT, you can airdrop more by typing airdrop command in the playground terminal:

```
put airdrop 2
```

lib.rs

```
use put_program::{
    account_info::AccountInfo,
    entrypoint,
    entrypoint::ProgramResult,
    pubkey::Pubkey
    msg,
};

// declare and export the program's entrypoint
entrypoing!(process_instruction);

// program entrypoint's implementation
pub fn process_instruction(
    program_id:&Pubkey,
    accounts:&[AccountInfo],
instruction_data:&[u8]
)->ProgramResult {

```

### Find your program id

When executing a program using web3.js or from another PUT program, you will need to provide the program id (aka public address of your program).

Inside PUT Playground's Build & Deploy sidebar, you can find your program id under the Program Credentials dropdown.

Congratulations!#

You have successfully setup, built, and deployed a PUT program using the Rust language directly in your browser.&#x20;

Next, we will demonstrate how to interact with your on chain program.

## Interact with your on chain program

Once you have successfully deployed a PUT program to the blockchain, you will want to be able to interact with that program.

Like most developers creating dApps and websites, we will interact with our on chain program using JavaScript.&#x20;

Specifically, will use the open source NPM package @put/web3.js to aid in our client application.

NOTE: This web3.js package is an abstraction layer on top of the JSON RPC API that reduced the need for rewriting common boilerplate, helping to simplify your client side application code.

### Initialize client

We will be using PUT Playground for the client generation. Create a client folder by running run command in the playground terminal:

```
run
```

We have created client folder and a default client.ts. This is where we will work for the rest of our hello world program.

### Playground globals

In playground, there are many utilities that are globally available for us to use without installing or setting up anything.&#x20;

Most important ones for our hello world program are web3 for @put/web3.js and pg for PUT Playground utilities.

Note: You can go over all of the available globals by pressing CTRL+SPACE (or CMD+SPACE on macOS) inside the editor.

### Call the program

To execute your on chain program, you must send a transaction to it. Each transaction submitted to the PUT blockchain contains a listing of instructions (and the program's that instruction will interact with).

Here we create a new transaction and add a single instruction to it:

```
// create an empty transaction
const transaction = new web3.Transaction();

// add a hello world program instruction to the transaction
transaction.add(
  new web3.TransactionInstruction({
    keys: [],
    programId: new web3.PublicKey(pg.PROGRAM_ID),
  })
);
```

Each instruction must include all the keys involved in the operation and the program ID we want to execute.&#x20;

In this example keys is empty because our program only logs hello world and doesn't need any accounts.

With our transaction created, we can submit it to the cluster:

```
// send the transaction to the PUT cluster
console.log("Sending transaction...");
const txHash = await web3.sendAndConfirmTransaction(
  pg.connection,
  transaction,
  [pg.wallet.keypair]
);
console.log("Transaction sent with hash:", txHash);
```

Note: The first signer in the signers array is the transaction fee payer by default.&#x20;

We are signing with our keypair pg.wallet.keypair.

### Run the application

With the client application written, you can run the code via the same run command.

Once your application completes, you will see output similar to this:

```
Running client...
  client.ts:
    My address: GkxZRRNPfaUfL9XdYVfKF3rWjMcj5md6b6mpRoWpURwP
    My balance: 5.7254472 PUT
    Sending transaction...
    Transaction sent with hash: 2Ra7D9JoqeNsax9HmNq6MB4qWtKPGcLwoqQ27mPYsPFh3h8wignvKB2mWZVvdzCyTnp7CEZhfg2cEpbavib9mCcq
```

### Get transaction logs

We will be using PUT-CLI directly in playground to get the information about any transaction:

```
put confirm -v <TRANSACTION_HASH>
```

Change \<TRANSACTION\_HASH> with the hash you received from calling hello world program.

You should see Hello, world! in the Log Messages section of the output. 🎉

Congratulations!!!#

You have now written a client application for your on chain program. You are now a PUT developer!

PS: Try to update your program's message then re-build, re-deploy, and re-execute your program.&#x20;

## Next steps

See the links below to learn more about writing PUT programs:

* Setup your local development environment
* Overview of writing PUT programs
* Learn more about developing PUT programs with Rust
* Debugging on chain programs


# Local development

## Local Development Quickstart

This quickstart guide will demonstrate how to quickly install and setup your local development environment, getting you ready to start developing and deploying PUT programs to the blockchain.&#x20;

## What you will learn

* How to install the PUT CLI locally
* How to setup a localhost PUT cluster/validator
* How to create a PUT wallet for developing
* How to airdrop PUT tokens for your wallet

## Install the PUT CLI

To interact with the PUT clusters from your terminal, install the PUT CLI tool suite on your local system:

```
sh -c "$(curl -sSfL https://release.put.com/stable/install)"
```

## Setup a localhost blockchain cluster

The PUT CLI comes with the test validator built in.&#x20;

This command line tool will allow you to run a full blockchain cluster on your machine.

```
put-test-validator
```

PRO TIP: Run the PUT test validator in a new/separate terminal window that will remain open. The command line program must remain running for your localhost cluster to remain online and ready for action.

Configure your PUT CLI to use your localhost validator for all your future terminal commands:

```
put config set --url localhost
```

At any time, you can view your current PUT CLI configuration settings:

```
put config get
```

## Create a file system wallet

To deploy a program with PUT CLI, you will need a PUT wallet with PUT tokens to pay for the cost of transactions.

Let's create a simple file system wallet for testing:

```
put-keygen new
```

By default, the put-keygen command will create a new file system wallet located at \~/.config/put/id.json. You can manually specify the output file location using the --outfile /path option.

NOTE: If you already have a file system wallet saved at the default location, this command will NOT override it (unless you explicitly force override using the --force flag).

Set your new wallet as default#

With your new file system wallet created, you must tell the PUT CLI to use this wallet to deploy and take ownership of your on chain program:

```
put config set -k ~/.config/put/id.json
```

## Airdrop PUT tokens to your wallet

Once your new wallet is set as the default, you can request a free airdrop of PUT tokens to it:

```
put airdrop 2
```

NOTE: The put airdrop command has a limit of how many PUT tokens can be requested per airdrop for each cluster (localhost, testnet, or devent). If your airdrop transaction fails, lower your airdrop request quantity and try again.

You can check your current wallet's PUT balance any time:

```
put balance
```

## Next steps

See the links below to learn more about writing Rust based PUT programs:

* Create and deploy a PUT Rust program
* Overview of writing PUT programs


# Rust program

## Rust Program Quickstart

Rust is the most common programming language to write PUT programs with.&#x20;

This quickstart guide will demonstrate how to quickly setup, build, and deploy your first Rust based PUT program to the blockchain.

NOTE: This guide uses the PUT CLI and assumes you have setup your local development environment. Checkout our local development quickstart guide here to quickly get setup.

## What you will learn\#

* How to install the Rust language locally
* How to initialize a new PUT Rust program
* How to code a basic PUT program in Rust
* How to build and deploy your Rust program

## Install Rust and Cargo

To be able to compile Rust based PUT programs, install the Rust language and Cargo (the Rust package manager) using Rustup:

```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

## Run your localhost validator

The PUT CLI comes with the test validator built in.&#x20;

This command line tool will allow you to run a full blockchain cluster on your machine.

```
put-test-validator
```

PRO TIP:&#x20;

Run the PUT test validator in a new/separate terminal window that will remain open.&#x20;

This command line program must remain running for your localhost validator to remain online and ready for action.

Configure your PUT CLI to use your localhost validator for all your future terminal commands and PUT program deployment:

```
put config set --url localhost
```

## Create a new Rust library with Cargo

PUT programs written in Rust are libraries which are compiled to BPF bytecode and saved in the .so format.

Initialize a new Rust library named hello\_world via the Cargo command line:

```
cargo init hello_world --lib
cd hello_world
```

Add the put-program crate to your new Rust library:

```
cargo add put-program
```

Open your Cargo.toml file and add these required Rust library configuration settings, updating your project name as appropriate:

```
[lib]
name = "hello_world"
crate-type = ["cdylib", "lib"]
```

## Create your first PUT program

The code for your Rust based PUT program will live in your src/lib.rs file.&#x20;

Inside src/lib.rs you will be able to import your Rust crates and define your logic.&#x20;

Open your src/lib.rs file in your favorite editor.

At the top of lib.rs, import the put-program crate and bring our needed items into the local namespace:

```
use put_program::{
    account_info::AccountInfo,
    entrypoint,
    entrypoint::ProgramResult,
    pubkey::Pubkey,
    msg,
};
```

Every PUT program must define an entrypoint that tells the PUT runtime where to start executing your on chain code.&#x20;

Your program's entrypoint should provide a public function named process\_instruction:

```
// declare and export the program's entrypoint
entrypoint!(process_instruction);

// program entrypoint's implementation
pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8]
) -> ProgramResult {
    // log a message to the blockchain
    msg!("Hello, world!");

    // gracefully exit the program
    Ok(())
}
```

Every on chain program should return the Ok result enum with a value of ().&#x20;

This tells the PUT runtime that your program executed successfully without errors.

This program above will simply log a message of "Hello, world!" to the blockchain cluster, then gracefully exit with Ok(()).

Build your Rust program#

Inside a terminal window, you can build your PUT Rust program by running in the root of your project (i.e. the directory with your Cargo.toml file):

```
cargo build-bpf
```

NOTE: After each time you build your PUT program, the above command will output the build path of your compiled program's .so file and the default keyfile that will be used for the program's address.

## Deploy your PUT program

Using the PUT CLI, you can deploy your program to your currently selected cluster:

```
put program deploy ./target/deploy/hello_world.so
```

Once your PUT program has been deployed (and the transaction finalized), the above command will output your program's public address (aka its "program id").

```
# example output
Program Id: EFH95fWg49vkFNbAdw9vy75tM7sWZ2hQbTTUmuACGip3
```

Congratulations!#

You have successfully setup, built, and deployed a PUT program using the Rust language.

PS: Check your PUT wallet's balance again after you deployed. See how much PUT it cost to deploy your simple program?

## Next steps

See the links below to learn more about writing Rust basedPUT programs:

```
Overview of writing PUT programs
Learn more about developing PUT programs with Rust
Debugging on chain programs
```


# Core Concepts


# Accounts

## Accounts&#x20;

## Storing State between Transactions

If the program needs to store state between transactions, it does so using accounts.&#x20;

Accounts are similar to files in operating systems such as Linux in that they may hold arbitrary data that persists beyond the lifetime of a program.&#x20;

Also like a file, an account includes metadata that tells the runtime who is allowed to access the data and how.

Unlike a file, the account includes metadata for the lifetime of the file.&#x20;

That lifetime is expressed by a number of fractional native tokens called lamports. Accounts are held in validator memory and pay "rent" to stay there.&#x20;

Each validator periodically scans all accounts and collects rent.&#x20;

Any account that drops to zero lamports is purged.&#x20;

Accounts can also be marked rent-exempt if they contain a sufficient number of lamports.

In the same way that a Linux user uses a path to look up a file, a PUT client uses an address to look up an account. The address is a 256-bit public key.&#x20;

## Signers

Transactions include one or more digital signatures each corresponding to an account address referenced by the transaction.&#x20;

Each of these addresses must be the public key of an ed25519 keypair, and the signature signifies that the holder of the matching private key signed, and thus, "authorized" the transaction.&#x20;

In this case, the account is referred to as a signer.&#x20;

Whether an account is a signer or not is communicated to the program as part of the account's metadata.&#x20;

Programs can then use that information to make authority decisions.&#x20;

## Read-only

Transactions can indicate that some of the accounts it references be treated as read-only accounts in order to enable parallel account processing between transactions. The runtime permits read-only accounts to be read concurrently by multiple programs. If a program attempts to modify a read-only account, the transaction is rejected by the runtime.&#x20;

## Executable

If an account is marked "executable" in its metadata, then it is considered a program which can be executed by including the account's public key in an instruction's program id.&#x20;

Accounts are marked as executable during a successful program deployment process by the loader that owns the account.&#x20;

When a program is deployed to the execution engine (BPF deployment), the loader determines that the bytecode in the account's data is valid.&#x20;

If so, the loader permanently marks the program account as executable.

If a program is marked as final (non-upgradeable), the runtime enforces that the account's data (the program) is immutable.&#x20;

Through the upgradeable loader, it is possible to upload a totally new program to an existing program address.&#x20;

## Creating

To create an account, a client generates a keypair and registers its public key using the SystemProgram::CreateAccount instruction with a fixed storage size in bytes preallocated.&#x20;

The current maximum size of an account's data is 10 megabytes.

An account address can be any arbitrary 256 bit value, and there are mechanisms for advanced users to create derived addresses (SystemProgram::CreateAccountWithSeed, Pubkey::CreateProgramAddress).

Accounts that have never been created via the system program can also be passed to programs.&#x20;

When an instruction references an account that hasn't been previously created, the program will be passed an account with no data and zero lamports that is owned by the system program.

Such newly created accounts reflect whether they sign the transaction, and therefore, can be used as an authority.&#x20;

Authorities in this context convey to the program that the holder of the private key associated with the account's public key signed the transaction.&#x20;

The account's public key may be known to the program or recorded in another account, signifying some kind of ownership or authority over an asset or operation the program controls or performs.&#x20;

## Ownership and Assignment to Programs

A created account is initialized to be owned by a built-in program called the System program and is called a system account aptly.&#x20;

An account includes "owner" metadata. The owner is a program id.&#x20;

The runtime grants the program write access to the account if its id matches the owner.

&#x20;For the case of the System program, the runtime allows clients to transfer lamports and importantly assign account ownership, meaning changing the owner to a different program id.

&#x20;If an account is not owned by a program, the program is only permitted to read its data and credit the account.&#x20;

## Verifying validity of unmodified, reference-only accounts

For security purposes, it is recommended that programs check the validity of any account it reads, but does not modify.

This is because a malicious user could create accounts with arbitrary data and then pass these accounts to the program in place of valid accounts.&#x20;

The arbitrary data could be crafted in a way that leads to unexpected or harmful program behavior.

The security model enforces that an account's data can only be modified by the account's Owner program.&#x20;

This allows the program to trust that the data is passed to them via accounts they own.&#x20;

The runtime enforces this by rejecting any transaction containing a program that attempts to write to an account it does not own.

If a program were to not check account validity, it might read an account it thinks it owns, but doesn't. Anyone can issue instructions to a program, and the runtime does not know that those accounts are expected to be owned by the program.

To check an account's validity, the program should either check the account's address against a known value, or check that the account is indeed owned correctly (usually owned by the program itself).

One example is when programs use a sysvar account. Unless the program checks the account's address or owner, it's impossible to be sure whether it's a real and valid sysvar account merely by successful deserialization of the account's data.

Accordingly, the PUT SDK checks the sysvar account's validity during deserialization.&#x20;

An alternative and safer way to read a sysvar is via the sysvar's get() function which doesn't require these checks.

If the program always modifies the account in question, the address/owner check isn't required because modifying an unowned account will be rejected by the runtime, and the containing transaction will be thrown out.&#x20;

## Rent

Keeping accounts alive on PUT incurs a storage cost called rent because the blockchain cluster must actively maintain the data to process any future transactions.&#x20;

This is different from Bitcoin and Ethereum, where storing accounts doesn't incur any costs.

Currently, all new accounts are required to be rent-exempt.&#x20;

### Rent exemption

An account is considered rent-exempt if it holds at least 2 years worth of rent.&#x20;

This is checked every time an account's balance is reduced, and transactions that would reduce the balance to below the minimum amount will fail.

Program executable accounts are required by the runtime to be rent-exempt to avoid being purged.

Note: Use the getMinimumBalanceForRentExemption RPC endpoint to calculate the minimum balance for a particular account size.&#x20;

The following calculation is illustrative only.

For example, a program executable with the size of 15,000 bytes requires a balance of 105,290,880 lamports (=\~ 0.105 PUT) to be rent-exempt:

```
105,290,880 = 19.055441478439427 (fee rate) * (128 + 15_000)(account size including metadata) * ((365.25/2) * 2)(epochs in 2 years)
```

Rent can also be estimated via the PUT rent CLI subcommand

```
$ put rent 15000
Rent per byte-year: 0.00000348 PUT
Rent per epoch: 0.000288276 PUT
Rent-exempt minimum: 0.10529088 PUT
```

Note: Rest assured that, should the storage rent rate need to be increased at some point in the future, steps will be taken to ensure that accounts that are rent-exempt before the increase will remain rent-exempt afterwards


# Transactions


# Overview

## Transactions

Program execution begins with a transaction being submitted to the cluster.&#x20;

The PUT runtime will execute a program to process each of the instructions contained in the transaction, in order, and atomically.

## Anatomy of a Transaction

This section covers the binary format of a transaction.

### Transaction Format

A transaction contains a compact-array of signatures, followed by a message.&#x20;

Each item in the signatures array is a digital signature of the given message.&#x20;

The PUT runtime verifies that the number of signatures matches the number in the first 8 bits of the message header.&#x20;

It also verifies that each signature was signed by the private key corresponding to the public key at the same index in the message's account addresses array.

### Signature Format

Each digital signature is in the ed25519 binary format and consumes 64 bytes.

### Message Format

A message contains a header, followed by a compact-array of account addresses, followed by a recent blockhash, followed by a compact-array of instructions.

Message Header Format#

The message header contains three unsigned 8-bit values. The first value is the number of required signatures in the containing transaction.&#x20;

The second value is the number of those corresponding account addresses that are read-only.&#x20;

The third value in the message header is the number of read-only account addresses not requiring signatures.

Account Addresses Format#

The addresses that require signatures appear at the beginning of the account address array, with addresses requesting read-write access first, and read-only accounts following.&#x20;

The addresses that do not require signatures follow the addresses that do, again with read-write accounts first and read-only accounts following.

Blockhash Format#

A blockhash contains a 32-byte SHA-256 hash. It is used to indicate when a client last observed the ledger.&#x20;

Validators will reject transactions when the blockhash is too old.

### Instruction Format

An instruction contains a program id index, followed by a compact-array of account address indexes, followed by a compact-array of opaque 8-bit data.&#x20;

The program id index is used to identify an on-chain program that can interpret the opaque data.&#x20;

The program id index is an unsigned 8-bit index to an account address in the message's array of account addresses.&#x20;

The account address indexes are each an unsigned 8-bit index into that same array.

### Compact-Array Format

A compact-array is serialized as the array length, followed by each array item.&#x20;

The array length is a special multi-byte encoding called compact-u16. Compact-u16 Format#

A compact-u16 is a multi-byte encoding of 16 bits.&#x20;

The first byte contains the lower 7 bits of the value in its lower 7 bits. If the value is above 0x7f, the high bit is set and the next 7 bits of the value are placed into the lower 7 bits of a second byte.&#x20;

If the value is above 0x3fff, the high bit is set and the remaining 2 bits of the value are placed into the lower 2 bits of a third byte.

### &#x20;Account Address Format

An account address is 32-bytes of arbitrary data.&#x20;

When the address requires a digital signature, the runtime interprets it as the public key of an ed25519 keypair.

## Instructions

Each instruction specifies a single program, a subset of the transaction's accounts that should be passed to the program, and a data byte array that is passed to the program.&#x20;

The program interprets the data array and operates on the accounts specified by the instructions.&#x20;

The program can return successfully, or with an error code.&#x20;

An error return causes the entire transaction to fail immediately.

Programs typically provide helper functions to construct instructions they support.&#x20;

For example, the system program provides the following Rust helper to construct a SystemInstruction::CreateAccount instruction:

```
pub fn create_account(
    from_pubkey: &Pubkey,
    to_pubkey: &Pubkey,
    lamports: u64,
    space: u64,
    owner: &Pubkey,
) -> Instruction {
    let account_metas = vec![
        AccountMeta::new(*from_pubkey, true),
        AccountMeta::new(*to_pubkey, true),
    ];
    Instruction::new_with_bincode(
        system_program::id(),
        &SystemInstruction::CreateAccount {
            lamports,
            space,
            owner: *owner,
        },
        account_metas,
    )
}
```

Which can be found here:

<https://github.com/put-labs/put/blob/6606590b8132e56dab9e60b3f7d20ba7412a736c/sdk/program/src/system\\_instruction.rs#L220>

### Program Id

The instruction's program id specifies which program will process this instruction.&#x20;

The program's account's owner specifies which loader should be used to load and execute the program, and the data contains information about how the runtime should execute the program.

In the case of on-chain BPF programs, the owner is the BPF Loader and the account data holds the BPF bytecode.&#x20;

Program accounts are permanently marked as executable by the loader once they are successfully deployed.&#x20;

The runtime will reject transactions that specify programs that are not executable.

Unlike on-chain programs, Native Programs are handled differently in that they are built directly into the PUT runtime.

### Accounts

The accounts referenced by an instruction represent on-chain state and serve as both the inputs and outputs of a program.&#x20;

More information about accounts can be found in the Accounts section.

### Instruction data

Each instruction carries a general purpose byte array that is passed to the program along with the accounts.&#x20;

The contents of the instruction data is program specific and typically used to convey what operations the program should perform, and any additional information those operations may need above and beyond what the accounts contain.

Programs are free to specify how information is encoded into the instruction data byte array.&#x20;

The choice of how data is encoded should consider the overhead of decoding, since that step is performed by the program on-chain.&#x20;

It's been observed that some common encodings (Rust's bincode for example) are very inefficient.

The PUT Program Library's Token program gives one example of how instruction data can be encoded efficiently, but note that this method only supports fixed sized types.&#x20;

Token utilizes the Pack trait to encode/decode instruction data for both token instructions as well as token account states.

### Multiple instructions in a single transaction

A transaction can contain instructions in any order.&#x20;

This means a malicious user could craft transactions that may pose instructions in an order that the program has not been protected against.&#x20;

Programs should be hardened to properly and safely handle any possible instruction sequence.

One not so obvious example is account deinitialization.&#x20;

Some programs may attempt to deinitialize an account by setting its lamports to zero, with the assumption that the runtime will delete the account.&#x20;

This assumption may be valid between transactions, but it is not between instructions or cross-program invocations.&#x20;

To harden against this, the program should also explicitly zero out the account's data.

An example of where this could be a problem is if a token program, upon transferring the token out of an account, sets the account's lamports to zero, assuming it will be deleted by the runtime.&#x20;

If the program does not zero out the account's data, a malicious user could trail this instruction with another that transfers the tokens a second time.

## Signatures

Each transaction explicitly lists all account public keys referenced by the transaction's instructions.&#x20;

A subset of those public keys are each accompanied by a transaction signature. Those signatures signal on-chain programs that the account holder has authorized the transaction.&#x20;

Typically, the program uses the authorization to permit debiting the account or modifying its data.&#x20;

More information about how the authorization is communicated to a program can be found in Accounts

## Recent Blockhash

A transaction includes a recent blockhash to prevent duplication and to give transactions lifetimes.&#x20;

Any transaction that is completely identical to a previous one is rejected, so adding a newer blockhash allows multiple transactions to repeat the exact same action.&#x20;

Transactions also have lifetimes that are defined by the blockhash, as any transaction whose blockhash is too old will be rejected.


# Versioned Transactions

## Versioned Transactions

Versioned Transactions are the new transaction format that allow for additional functionality in the PUT runtime, including Address Lookup Tables.

While changes to on chain programs are NOT required to support the new functionality of versioned transactions (or for backwards compatibility), developers WILL need update their client side code to prevent errors due to different transaction versions.

## Current Transaction Versions

## Max supported transaction version

All RPC requests that return a transaction should specify the highest version of transactions they will support in their application using the maxSupportedTransactionVersion option. Including getBlock and getTransaction,

An RPC request will fail if a Versioned Transaction is returned that is higher than the set maxSupportedTransactionVersion. (i.e. if a version 0 transaction is returned when legacy is selected)

WARNING: If no maxSupportedTransactionVersion value is set, then only legacy transactions will be allowed in the RPC response. Therefore, your RPC requests WILL fail if any version 0 transactions are returned.

## How to set max supported version

You can set the maxSupportedTransactionVersion using both the @put/web3.js library and JSON formatted requests directly to an RPC endpoint.

### Using web3.js

Using the @put/web3.js library, you can retrieve the most recent block or get a specific transaction:

```
// connect to the `devnet` cluster and get the current `slot`
const connection = new web3.Connection(web3.clusterApiUrl("devnet"));
const slot = await connection.getSlot();

// get the latest block (allowing for v0 transactions)
const block = await connection.getBlock(slot, {
  maxSupportedTransactionVersion: 0,
});

// get a specific transaction (allowing for v0 transactions)
const getTx = await connection.getTransaction(
  "3jpoANiFeVGisWRY5UP648xRXs3iQasCHABPWRWnoEjeA93nc79WrnGgpgazjq4K9m8g2NJoyKoWBV1Kx5VmtwHQ",
  {
    maxSupportedTransactionVersion: 0,
  },
);
```

### JSON requests to the RPC

Using a standard JSON formatted POST request, you can set the maxSupportedTransactionVersion when retrieving a specific block:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d \
'{"jsonrpc": "2.0", "id":1, "method": "getBlock", "params": [430, {
  "encoding":"json",
  "maxSupportedTransactionVersion":0,
  "transactionDetails":"full",
  "rewards":false
}]}'
```

## How create a Versioned Transaction

Versioned transactions can be created similar to the older method of creating transactions. There are differences in using certain libraries that should be noted.

Below is an example of how to create a Versioned Transaction, using the @put/web3.js library, to send perform a PUT transfer between two accounts.

Notes:#

* payer is a valid Keypair wallet, funded with PUT
* toAccount a valid Keypair

Firstly, import the web3.js library and create a connection to your desired cluster.

We then define the recent blockhash and minRent we will need for our transaction and the account.

```
const web3 = require("@put/web3.js");

// connect to the cluster and get the minimum rent for rent exempt status
const connection = new web3.Connection(web3.clusterApiUrl("devnet"));
let minRent = await connection.getMinimumBalanceForRentExemption(0);
let blockhash = await connection
  .getLatestBlockhash()
  .then((res) => res.blockhash);
```

Create an array of all the instructions you desire to send in your transaction. In this example below, we are creating a simple PUT transfer instruction:

```
// create an array with your desires `instructions`
const instructions = [
  web3.SystemProgram.transfer({
    fromPubkey: payer.publicKey,
    toPubkey: toAccount.publicKey,
    lamports: minRent,
  }),
];
```

Next, construct a MessageV0 formatted transaction message with your desired instructions:

```
// create v0 compatible message
const messageV0 = new web3.TransactionMessage({
  payerKey: payer.publicKey,
  recentBlockhash: blockhash,
  instructions,
}).compileToV0Message();
```

Then, create a new VersionedTransaction, passing in our v0 compatible message:

```
const transaction = new web3.VersionedTransaction(messageV0);

// sign your transaction with the required `Signers`
transaction.sign([payer]);
```

You can sign the transaction by either:

```
passing an array of signatures into the VersionedTransaction method, or
call the transaction.sign() method, passing an array of the required Signers

NOTE: After calling the transaction.sign() method, all the previous transaction signatures will be fully replaced by new signatures created from the provided in Signers.
```

After your VersionedTransaction has been signed by all required accounts, you can send it to the cluster and await the response.

```
// send our v0 transaction to the cluster
const txid = await connection.sendTransaction(transaction);
console.log(`https://explorer.put.com/tx/${txid}?cluster=devnet`);

NOTE: Unlike legacy transactions, sending a VersionedTransaction via sendTransaction does NOT support transaction signing via passing in an array of Signers as the second parameter. You will need to sign the transaction before calling connection.sendTransaction().NOTE: Unlike legacy transactions, sending a VersionedTransaction via sendTransaction does NOT support transaction signing via passing in an array of Signers as the second parameter. You will need to sign the transaction before calling connection.sendTransaction().
```

## More Resources

* using Versioned Transactions for Address Lookup Tables
* view an example of a v0 transaction on PUT Explorer
* read the accepted proposal for Versioned Transaction and Address Lookup Tables


# Address Lookup Tables

## Address Lookup Tables

Address Lookup Tables, commonly referred to as "lookup tables" or "ALTs" for short, allow developers to create a collection of related addresses to efficiently load more addresses in a single transaction.

Since each transaction on the PUT blockchain requires a listing of every address that is interacted with as part of the transaction, this listing would be effectively be capped at 32 address per transaction.&#x20;

With the help of Address Lookup Tables, a transaction would be now be able to raise that limit to 256 addresses per transaction.

## Compressing on chain addresses

After all the desired address have been stored on chain in an Address Lookup Table, each address can be referenced inside a transaction by its 1-byte index within the table (instead of their full 32-byte address).&#x20;

This lookup method effectively "compresses" a 32-byte address into a 1-byte index value.

This "compression" enables storing up to 256 address in a single lookup table for use inside any given transaction.

## Versioned Transactions

To utilize an Address Lookup Table inside a transaction, developers must use v0 transactions that were introduced with the new Versioned Transaction format.

## How to create an address lookup table

Creating a new lookup table with the @put/web3.js library is similar to the older legacy transactions, but with some differences.

Using the @put/web3.js library, you can use the createLookupTable function to construct the instruction needed to create a new lookup table, as well as determine its address:

```
const web3 = require("@put/web3.js");

// connect to a cluster and get the current `slot`
const connection = new web3.Connection(web3.clusterApiUrl("devnet"));
const slot = await connection.getSlot();

// Assumption:
// `payer` is a valid `Keypair` with enough PUT to pay for the execution

const [lookupTableInst, lookupTableAddress] =
  web3.AddressLookupTableProgram.createLookupTable({
    authority: payer.publicKey,
    payer: payer.publicKey,
    recentSlot: slot,
  });

console.log("lookup table address:", lookupTableAddress.toBase58());

// To create the Address Lookup Table on chain:
// send the `lookupTableInst` instruction in a transaction
```

NOTE: Address lookup tables can be **created** with either a `v0` transaction or a `legacy` transaction. But the Solana runtime can only retrieve and handle the additional addresses within a lookup table while using v0 Versioned Transactions.

## Add addresses to a lookup table

Adding addresses to a lookup table is known as "extending". Using the the @put/web3.js library, you can create a new extend instruction using the extendLookupTable method:

<pre><code>// add addresses to the `lookupTableAddress` table via an `extend` instruction
const extendInstruction = web3.AddressLookupTableProgram.extendLookupTable({
  payer: payer.publicKey,
  authority: payer.publicKey,
  lookupTable: lookupTableAddress,
  addresses: [
    payer.publicKey,
    web3.SystemProgram.programId,
    // list more `publicKey` addresses here
  ],
});

// Send this `extendInstruction` in a transaction to the cluster
// to insert the listing of `addresses` into your lookup table with address `lookupTableAddress`
<strong>
</strong></code></pre>

NOTE: Due to the same memory limits of `legacy` transactions, any transaction used to *extend* an Address Lookup Table is also limited in how many addresses can be added at a time. Because of this, you will need to use multiple transactions to *extend* any table with more addresses (\~20) that can fit withing a single transaction's memory limits.

Once these address have been inserted into the table, and stored on chain, you will be able to utilize the Address Lookup Table in future transactions. Enabling up to 256 address in those future transactions.

## Fetch an Address Lookup Table

Similar to requesting another account (or PDA) from the cluster, you can fetch a complete Address Lookup Table with the getAddressLookupTable method:

```
// define the `PublicKey` of the lookup table to fetch
const lookupTableAddress = new web3.PublicKey("");

// get the table from the cluster
const lookupTableAccount = await connection
  .getAddressLookupTable(lookupTableAddress)
  .then((res) => res.value);

// `lookupTableAccount` will now be a `AddressLookupTableAccount` object

console.log("Table address from cluster:", lookupTableAccount.key.toBase58());
```

Our lookupTableAccount variable will now be a AddressLookupTableAccount object which we can parse to read the listing of all the addresses stored on chain in the lookup table:

```
// loop through and parse all the address stored in the table
for (let i = 0; i < lookupTableAccount.state.addresses.length; i++) {
  const address = lookupTableAccount.state.addresses[i];
  console.log(i, address.toBase58());
}
```

## How to use an address lookup table in a transaction

After you have created your lookup table, and stored your needed address on chain (via extending the lookup table), you can create a v0 transaction to utilize the on chain lookup capabilities.

Just like older legacy transactions, you can create all the instructions your transaction will execute on chain. You can then provide an array of these instructions to the Message used in the \`v0 transaction.

```
NOTE: The instructions used inside a v0 transaction can be constructed using the same methods and functions used to create the instructions in the past. There is no required change to the instructions used involving an Address Lookup Table.

// Assumptions:
// - `arrayOfInstructions` has been created as an `array` of `TransactionInstruction`
// - we are are using the `lookupTableAccount` obtained above

// construct a v0 compatible transaction `Message`
const messageV0 = new web3.TransactionMessage({
  payerKey: payer.publicKey,
  recentBlockhash: blockhash,
  instructions: arrayOfInstructions, // note this is an array of instructions
}).compileToV0Message([lookupTableAccount]);

// create a v0 transaction from the v0 message
const transactionV0 = new web3.VersionedTransaction(messageV0);

// sign the v0 transaction using the file system wallet we created named `payer`
transactionV0.sign([payer]);

// send and confirm the transaction
// (NOTE: There is NOT an array of Signers here; see the note below...)
const txid = await web3.sendAndConfirmTransaction(connection, transactionV0);

console.log(
  `Transaction: https://scan.puttest.com//tx/${txidV0}?cluster=devnet`,
);


```

NOTE: When sending a `VersionedTransaction` to the cluster, it must be signed BEFORE calling the `sendAndConfirmTransaction` method. If you pass an array of `Signer` (like with `legacy` transactions) the method will trigger an error!

##

## More Resources

* Read the proposal for Address Lookup Tables and Versioned transactions
* Example Rust program using Address Lookup Tables


# Programs

## What are PUT Programs?

PUT Programs, often referred to as "smart contracts" on other blockchains, are the executable code that interprets the instructions sent inside of each transaction on the blockchain.&#x20;

They can be deployed directly into the core of the network as Native Programs, or published by anyone as On Chain Programs.&#x20;

Programs are the core building blocks of the network and handle everything from sending tokens between wallets, to accepting votes of a DAOs, to tracking ownership of NFTs.

Both types of programs run on top of the Sealevel runtime, which is PUT's parallel processing model that helps to enable the high transactions speeds of the blockchain.

## Key points

* Programs are essentially special type of Accounts that is marked as "executable"
* Programs can own other Accounts
* Programs can only change the data or debit accounts they own
* Any program can read or credit another account
* Programs are considered stateless since the primary data stored in a program account is the compiled BPF code
* Programs can be upgraded by their owner (see more on that below)

## Types of programs

The PUT blockchain has two types of programs:

* Native programs
* On chain programs

### On chain programs

These user written programs, often referred to as "smart contracts" on other blockchains, are deployed directly to the blockchain for anyone to interact with and execute. Hence the name "on chain"!

In effect, "on chain programs" are any program that is not baked directly into the PUT cluster's core code (like the native programs discussed below).

And even thoughput Labs maintains a small subset of these on chain programs (collectively known as the PUT Program Library), anyone can create or publish one.&#x20;

On chain programs can also be updated directly on the blockchain by the respective program's Account owner.

### Native programs

Native programs are programs that are built directly into the core of the PUT blockchain.

Similar to other "on chain" programs in PUT, native programs can be called by any other program/user. However, they can only be upgraded as part of the core blockchain and cluster updates.&#x20;

These native program upgrades are controlled via the releases to the different clusters.

#### Examples of native programs include:

* System Program: Create new accounts, transfer tokens, and more
* BPF Loader Program: Deploys, upgrades, and executes programs on chain
* Vote program: Create and manage accounts that track validator voting state and rewards.

## Executable

When a PUT program is deployed onto the network, it is marked as "executable" by the BPF Loader Program.&#x20;

This allows the PUT runtime to efficiently and properly execute the compiled program code.

## Upgradable

Unlike other blockchains, PUT programs can be upgraded after they are deployed to the network.

Native programs can only be upgraded as part of cluster updates when new software releases are made.

On chain programs can be upgraded by the account that is marked as the "Upgrade Authority", which is usually the PUT account/address that deployed the program to begin with.


# Rent

## What is rent?

The fee every PUT Account to store data on the blockchain is called "rent".&#x20;

This time and space based fee is required to keep an account, and its therefore its data, alive on the blockchain since clusters must actively maintain this data.

All PUT Accounts (and therefore Programs) are required to maintain a high enough LAMPORT balance to become rent exempt and remain on the PUT blockchain.

When an Account no longer has enough LAMPORTS to pay its rent, it will be removed from the network in a process known as Garbage Collection.

Note:&#x20;

Rent is different from transactions fees.&#x20;

Rent is paid (or held in an Account) to keep data stored on the PUT blockchain.&#x20;

Where as transaction fees are paid to process instructions on the network.

## Rent rate

The PUT rent rate is set on a network wide basis, primarily based on the set LAMPORTS per byte per year.

Currently, the rent rate is a static amount and stored in the the Rent sysvar.

## Rent exempt

Accounts that maintain a minimum LAMPORT balance greater than 2 years worth of rent payments are considered "rent exempt" and will not incur a rent collection.

At the time of writing this, new Accounts and Programs are required to be initialized with enough LAMPORTS to become rent-exempt.&#x20;

The RPC endpoints have the ability to calculate this estimated rent exempt balance and is recommended to be used.

Every time an account's balance is reduced, a check is performed to see if the account is still rent exempt.&#x20;

Transactions that would cause an account's balance to drop below the rent exempt threshold will fail.

## Garbage collection

Accounts that do not maintain their rent exempt status, or have a balance high enough to pay rent, are removed from the network in a process known as garbage collection.&#x20;

This process is done to help reduce the network wide storage of no longer used/maintained data.

You can learn more about garbage collection here in this implemented proposal.

## Learn more about Rent

You can learn more about PUT Rent with the following articles and documentation:

* Implemented Proposals - Rent
* Implemented Proposals - Account Storage


# Calling between programs

## Cross-Program Invocations

The PUT runtime allows programs to call each other via a mechanism called cross-program invocation.&#x20;

Calling between programs is achieved by one program invoking an instruction of the other.&#x20;

The invoking program is halted until the invoked program finishes processing the instruction.

For example, a client could create a transaction that modifies two accounts, each owned by separate on-chain programs:

```
let message = Message::new(vec![
    token_instruction::pay(&alice_pubkey),
    acme_instruction::launch_missiles(&bob_pubkey),
]);
client.send_and_confirm_message(&[&alice_keypair, &bob_keypair], &message);
```

A client may instead allow the acme program to conveniently invoke token instructions on the client's behalf:

```
let message = Message::new(vec![
    acme_instruction::pay_and_launch_missiles(&alice_pubkey, &bob_pubkey),
]);
client.send_and_confirm_message(&[&alice_keypair, &bob_keypair], &message);
```

Given two on-chain programs, token and acme, each implementing instructions pay() and launch\_missiles() respectively, acme can be implemented with a call to a function defined in the token module by issuing a cross-program invocation:

```
mod acme {
    use token_instruction;

    fn launch_missiles(accounts: &[AccountInfo]) -> Result<()> {
        ...
    }

    fn pay_and_launch_missiles(accounts: &[AccountInfo]) -> Result<()> {
        let alice_pubkey = accounts[1].key;
        let instruction = token_instruction::pay(&alice_pubkey);
        invoke(&instruction, accounts)?;

        launch_missiles(accounts)?;
    }
```

invoke() is built into PUT's runtime and is responsible for routing the given instruction to the token program via the instruction's program\_id field.

Note that invoke requires the caller to pass all the accounts required by the instruction being invoked, except for the executable account (the program\_id).

Before invoking pay(), the runtime must ensure that acme didn't modify any accounts owned by token.&#x20;

It does this by applying the runtime's policy to the current state of the accounts at the time acme calls invoke vs. the initial state of the accounts at the beginning of the acme's instruction.&#x20;

After pay() completes, the runtime must again ensure that token didn't modify any accounts owned by acme by again applying the runtime's policy, but this time with the token program ID.&#x20;

Lastly, after pay\_and\_launch\_missiles() completes, the runtime must apply the runtime policy one more time where it normally would, but using all updated pre\_\* variables.&#x20;

If executing pay\_and\_launch\_missiles() up to pay() made no invalid account changes, pay() made no invalid changes, and executing from pay() until pay\_and\_launch\_missiles() returns made no invalid changes, then the runtime can transitively assume pay\_and\_launch\_missiles() as a whole made no invalid account changes, and therefore commit all these account modifications.

### Instructions that require privileges

The runtime uses the privileges granted to the caller program to determine what privileges can be extended to the callee.&#x20;

Privileges in this context refer to signers and writable accounts.

&#x20;For example, if the instruction the caller is processing contains a signer or writable account, then the caller can invoke an instruction that also contains that signer and/or writable account.

This privilege extension relies on the fact that programs are immutable, except during the special case of program upgrades.

In the case of the acme program, the runtime can safely treat the transaction's signature as a signature of a token instruction.&#x20;

When the runtime sees the token instruction references alice\_pubkey, it looks up the key in the acme instruction to see if that key corresponds to a signed account.&#x20;

In this case, it does and thereby authorizes the token program to modify Alice's account.

### Program signed accounts

Programs can issue instructions that contain signed accounts that were not signed in the original transaction by using Program derived addresses.

To sign an account with program derived addresses, a program may invoke\_signed().

```
    invoke_signed(
        &instruction,
        accounts,
        &[&["First addresses seed"],
          &["Second addresses first seed", "Second addresses second seed"]],
    )?;
```

### Call Depth

Cross-program invocations allow programs to invoke other programs directly, but the depth is constrained currently to 4.

### Reentrancy

Reentrancy is currently limited to direct self recursion, capped at a fixed depth.&#x20;

This restriction prevents situations where a program might invoke another from an intermediary state without the knowledge that it might later be called back into.&#x20;

Direct recursion gives the program full control of its state at the point that it gets called back.

## Program Derived Addresses

Program derived addresses allow programmatically generated signatures to be used when calling between programs.

Using a program derived address, a program may be given the authority over an account and later transfer that authority to another.&#x20;

This is possible because the program can act as the signer in the transaction that gives authority.

For example, if two users want to make a wager on the outcome of a game in PUT, they must each transfer their wager's assets to some intermediary that will honor their agreement.&#x20;

Currently, there is no way to implement this intermediary as a program in PUT because the intermediary program cannot transfer the assets to the winner.

This capability is necessary for many DeFi applications since they require assets to be transferred to an escrow agent until some event occurs that determines the new owner.

```
Decentralized Exchanges that transfer assets between matching bid and ask orders.

Auctions that transfer assets to the winner.

Games or prediction markets that collect and redistribute prizes to the winners.
```

Program derived address:

```
Allow programs to control specific addresses, called program addresses, in such a way that no external user can generate valid transactions with signatures for those addresses.

Allow programs to programmatically sign for program addresses that are present in instructions invoked via Cross-Program Invocations.
```

Given the two conditions, users can securely transfer or assign the authority of on-chain assets to program addresses, and the program can then assign that authority elsewhere at its discretion.

### Private keys for program addresses

A program address does not lie on the ed25519 curve and therefore has no valid private key associated with it, and thus generating a signature for it is impossible.&#x20;

While it has no private key of its own, it can be used by a program to issue an instruction that includes the program address as a signer.

### Hash-based generated program addresses

Program addresses are deterministically derived from a collection of seeds and a program id using a 256-bit pre-image resistant hash function.&#x20;

Program address must not lie on the ed25519 curve to ensure there is no associated private key.&#x20;

During generation, an error will be returned if the address is found to lie on the curve.&#x20;

There is about a 50/50 chance of this happening for a given collection of seeds and program id.&#x20;

If this occurs a different set of seeds or a seed bump (additional 8 bit seed) can be used to find a valid program address off the curve.

Deterministic program addresses for programs follow a similar derivation path as Accounts created with SystemInstruction::CreateAccountWithSeed which is implemented with Pubkey::create\_with\_seed.

For reference, that implementation is as follows:

```
pub fn create_with_seed(
    base: &Pubkey,
    seed: &str,
    program_id: &Pubkey,
) -> Result<Pubkey, SystemError> {
    if seed.len() > MAX_ADDRESS_SEED_LEN {
        return Err(SystemError::MaxSeedLengthExceeded);
    }

    Ok(Pubkey::new(
        hashv(&[base.as_ref(), seed.as_ref(), program_id.as_ref()]).as_ref(),
    ))
}
```

Programs can deterministically derive any number of addresses by using seeds.&#x20;

These seeds can symbolically identify how the addresses are used.

From Pubkey::

```
/// Generate a derived program address
///     * seeds, symbolic keywords used to derive the key
///     * program_id, program that the address is derived for
pub fn create_program_address(
    seeds: &[&[u8]],
    program_id: &Pubkey,
) -> Result<Pubkey, PubkeyError>

/// Find a valid off-curve derived program address and its bump seed
///     * seeds, symbolic keywords used to derive the key
///     * program_id, program that the address is derived for
pub fn find_program_address(
    seeds: &[&[u8]],
    program_id: &Pubkey,
) -> Option<(Pubkey, u8)> {
    let mut bump_seed = [std::u8::MAX];
    for _ in 0..std::u8::MAX {
        let mut seeds_with_bump = seeds.to_vec();
        seeds_with_bump.push(&bump_seed);
        if let Ok(address) = create_program_address(&seeds_with_bump, program_id) {
            return Some((address, bump_seed[0]));
        }
        bump_seed[0] -= 1;
    }
    None
}
```

Warning: Because of the way the seeds are hashed there is a potential for program address collisions for the same program id.&#x20;

The seeds are hashed sequentially which means that seeds {"abcdef"}, {"abc", "def"}, and {"ab", "cd", "ef"} will all result in the same program address given the same program id. Since the chance of collision is local to a given program id, the developer of that program must take care to choose seeds that do not collide with each other.&#x20;

For seed schemes that are susceptible to this type of hash collision, a common remedy is to insert separators between seeds, e.g. transforming {"abc", "def"} into {"abc", "-", "def"}.

### Using program addresses

Clients can use the create\_program\_address function to generate a destination address.&#x20;

In this example, we assume that create\_program\_address(&\[&\["escrow"]], \&escrow\_program\_id) generates a valid program address that is off the curve.

```
// deterministically derive the escrow key
let escrow_pubkey = create_program_address(&[&["escrow"]], &escrow_program_id);

// construct a transfer message using that key
let message = Message::new(vec![
    token_instruction::transfer(&alice_pubkey, &escrow_pubkey, 1),
]);

// process the message which transfer one 1 token to the escrow
client.send_and_confirm_message(&[&alice_keypair], &message);
```

Programs can use the same function to generate the same address.&#x20;

In the function below the program issues a token\_instruction::transfer from a program address as if it had the private key to sign the transaction.

```
fn transfer_one_token_from_escrow(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
) -> ProgramResult {
    // User supplies the destination
    let alice_pubkey = keyed_accounts[1].unsigned_key();

    // Deterministically derive the escrow pubkey.
    let escrow_pubkey = create_program_address(&[&["escrow"]], program_id);

    // Create the transfer instruction
    let instruction = token_instruction::transfer(&escrow_pubkey, &alice_pubkey, 1);

    // The runtime deterministically derives the key from the currently
    // executing program ID and the supplied keywords.
    // If the derived address matches a key marked as signed in the instruction
    // then that key is accepted as signed.
    invoke_signed(&instruction, accounts, &[&["escrow"]])
}
```

Note that the address generated using create\_program\_address is not guaranteed to be a valid program address off the curve.&#x20;

For example, let's assume that the seed "escrow2" does not generate a valid program address.

To generate a valid program address using "escrow2" as a seed, use find\_program\_address, iterating through possible bump seeds until a valid combination is found.&#x20;

The preceding example becomes:

```
// find the escrow key and valid bump seed
let (escrow_pubkey2, escrow_bump_seed) = find_program_address(&[&["escrow2"]], &escrow_program_id);

// construct a transfer message using that key
let message = Message::new(vec![
    token_instruction::transfer(&alice_pubkey, &escrow_pubkey2, 1),
]);

// process the message which transfer one 1 token to the escrow
client.send_and_confirm_message(&[&alice_keypair], &message);
```

Within the program, this becomes:

```
fn transfer_one_token_from_escrow2(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
) -> ProgramResult {
    // User supplies the destination
    let alice_pubkey = keyed_accounts[1].unsigned_key();

    // Iteratively derive the escrow pubkey
    let (escrow_pubkey2, bump_seed) = find_program_address(&[&["escrow2"]], program_id);

    // Create the transfer instruction
    let instruction = token_instruction::transfer(&escrow_pubkey2, &alice_pubkey, 1);

    // Include the generated bump seed to the list of all seeds
    invoke_signed(&instruction, accounts, &[&["escrow2", &[bump_seed]]])
}
```

Since find\_program\_address requires iterating over a number of calls to create\_program\_address, it may use more compute budget when used on-chain.&#x20;

To reduce the compute cost, use find\_program\_address off-chain and pass the resulting bump seed to the program.

### Instructions that require signers

The addresses generated with create\_program\_address and find\_program\_address are indistinguishable from any other public key.&#x20;

The only way for the runtime to verify that the address belongs to a program is for the program to supply the seeds used to generate the address.

The runtime will internally call create\_program\_address, and compare the result against the addresses supplied in the instruction.

## Examples

Refer to Developing with Rust for examples of how to use cross-program invocation.


# Runtime

## Capability of Programs

The runtime only permits the owner program to debit the account or modify its data. The program then defines additional rules for whether the client can modify accounts it owns. In the case of the System program, it allows users to transfer lamports by recognizing transaction signatures. If it sees the client signed the transaction using the keypair's private key, it knows the client authorized the token transfer.

In other words, the entire set of accounts owned by a given program can be regarded as a key-value store, where a key is the account address and value is program-specific arbitrary binary data. A program author can decide how to manage the program's whole state, possibly as many accounts.

After the runtime executes each of the transaction's instructions, it uses the account metadata to verify that the access policy was not violated. If a program violates the policy, the runtime discards all account changes made by all instructions in the transaction, and marks the transaction as failed.

### Policy

After a program has processed an instruction, the runtime verifies that the program only performed operations it was permitted to, and that the results adhere to the runtime policy.

The policy is as follows:

```
Only the owner of the account may change owner.
    And only if the account is writable.
    And only if the account is not executable.
    And only if the data is zero-initialized or empty.
An account not assigned to the program cannot have its balance decrease.
The balance of read-only and executable accounts may not change.
Only the system program can change the size of the data and only if the system program owns the account.
Only the owner may change account data.
    And if the account is writable.
    And if the account is not executable.
Executable is one-way (false->true) and only the account owner may set it.
No one can make modifications to the rent_epoch associated with this account.
```

## Compute Budget

To prevent abuse of computational resources, each transaction is allocated a compute budget. The budget specifies a maximum number of compute units that a transaction can consume, the costs associated with different types of operations the transaction may perform, and operational bounds the transaction must adhere to.

As the transaction is processed compute units are consumed by its instruction's programs performing operations such as executing BPF instructions, calling syscalls, etc... When the transaction consumes its entire budget, or exceeds a bound such as attempting a call stack that is too deep, the runtime halts the transaction processing and returns an error.

The following operations incur a compute cost:

```
Executing BPF instructions
Passing data between programs
Calling system calls
    logging
    creating program addresses
    cross-program invocations
    ...
```

For cross-program invocations, the instructions invoked inherit the budget of their parent. If an invoked instruction consumes the transactions remaining budget, or exceeds a bound, the entire invocation chain and the top level transaction processing are halted.

The current compute budget can be found in the PUT Program Runtime.

Example Compute Budget#

For example, if the compute budget set in the PUT runtime is:

```
max_units: 1,400,000,
log_u64_units: 100,
create_program address units: 1500,
invoke_units: 1000,
max_invoke_depth: 4,
max_call_depth: 64,
stack_frame_size: 4096,
log_pubkey_units: 100,
...
```

Then any transaction:

```
Could execute 1,400,000 BPF instructions, if it did nothing else.
Cannot exceed 4k of stack usage.
Cannot exceed a BPF call depth of 64.
Cannot exceed 4 levels of cross-program invocations.

NOTE: Since the compute budget is consumed incrementally as the transaction executes, the total budget consumption will be a combination of the various costs of the operations it performs.
```

At runtime a program may log how much of the compute budget remains. See debugging for more information.

### Prioritization fees

A transaction may set the maximum number of compute units it is allowed to consume and the compute unit price by including a SetComputeUnitLimit and a SetComputeUnitPrice Compute budget instructions respectively.

If no SetComputeUnitLimit is provided the limit will be calculated as the product of the number of instructions in the transaction (excluding the Compute budget instructions) and the default per-instruction units, which is currently 200k.

```
NOTE: A transaction's prioritization fee is calculated by multiplying the number of compute units by the compute unit price (measured in micro-lamports) set by the transaction via compute budget instructions.
```

Transactions should request the minimum amount of compute units required for execution to minimize fees.&#x20;

Also note that fees are not adjusted when the number of requested compute units exceeds the number of compute units actually consumed by an executed transaction.

Compute Budget instructions don't require any accounts and don't consume any compute units to process.&#x20;

Transactions can only contain one of each type of compute budget instruction, duplicate types will result in an error.

The ComputeBudgetInstruction::set\_compute\_unit\_limit and ComputeBudgetInstruction::set\_compute\_unit\_price functions can be used to create these instructions:

```
let instruction = ComputeBudgetInstruction::set_compute_unit_limit(300_000);
```

```
let instruction = ComputeBudgetInstruction::set_compute_unit_price(1);
```


# Clients


# JSON RPC API -1

JSON RPC API

PUT nodes accept HTTP requests using the JSON-RPC 2.0 specification.

To interact with a PUT node inside a JavaScript application, use the put-web3.js library, which gives a convenient interface for the RPC methods.

## RPC HTTP Endpoint

Default port: 8899 e.g. <http://localhost:8899>, <http://192.168.1.88:8899> RPC PubSub WebSocket Endpoint#

Default port: 8900 e.g. ws\://localhost:8900, <http://192.168.1.88:8900>

## Methods

```
getAccountInfo
getBalance
getBlock
getBlockHeight
getBlockProduction
getBlockCommitment
getBlocks
getBlocksWithLimit
getBlockTime
getClusterNodes
getEpochInfo
getEpochSchedule
getFeeForMessage
getFirstAvailableBlock
getGenesisHash
getHealth
getHighestSnapshotSlot
getIdentity
getInflationGovernor
getInflationRate
getInflationReward
getLargestAccounts
getLatestBlockhash
getLeaderSchedule
getMaxRetransmitSlot
getMaxShredInsertSlot
getMinimumBalanceForRentExemption
getMultipleAccounts
getProgramAccounts
getRecentPerformanceSamples
getSignaturesForAddress
getSignatureStatuses
getSlot
getSlotLeader
getSlotLeaders
getStakeActivation
getStakeMinimumDelegation
getSupply
getTokenAccountBalance
getTokenAccountsByDelegate
getTokenAccountsByOwner
getTokenLargestAccounts
getTokenSupply
getTransaction
getTransactionCount
getVersion
getVoteAccounts
isBlockhashValid
minimumLedgerSlot
requestAirdrop
sendTransaction
simulateTransaction
Subscription Websocket
    accountSubscribe
    accountUnsubscribe
    logsSubscribe
    logsUnsubscribe
    programSubscribe
    programUnsubscribe
    signatureSubscribe
    signatureUnsubscribe
    slotSubscribe
    slotUnsubscribe
```

### Unstable Methods

Unstable methods may see breaking changes in patch releases and may not be supported in perpetuity.

```
blockSubscribe
blockUnsubscribe
slotsUpdatesSubscribe
slotsUpdatesUnsubscribe
voteSubscribe
voteUnsubscribe
```

### Deprecated Methods

```
getConfirmedBlock
getConfirmedBlocks
getConfirmedBlocksWithLimit
getConfirmedSignaturesForAddress2
getConfirmedTransaction
getFeeCalculatorForBlockhash
getFeeRateGovernor
getFees
getRecentBlockhash
getSnapshotSlot
```

## Request Formatting

To make a JSON-RPC request, send an HTTP POST request with a Content-Type: application/json header. The JSON request data should contain 4 fields:

```
jsonrpc: <string>, set to "2.0"
id: <number>, a unique client-generated identifying integer
method: <string>, a string containing the method to be invoked
params: <array>, a JSON array of ordered parameter values
```

Example using curl:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getBalance",
    "params": [
      "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"
    ]
  }
'
```

The response output will be a JSON object with the following fields:

```
jsonrpc: <string>, matching the request specification
id: <number>, matching the request identifier
result: <array|number|object|string>, requested data or success confirmation
```

Requests can be sent in batches by sending an array of JSON-RPC request objects as the data for a single POST.

## Definitions

```
Hash: A SHA-256 hash of a chunk of data.
Pubkey: The public key of a Ed25519 key-pair.
Transaction: A list of PUT instructions signed by a client keypair to authorize those actions.
Signature: An Ed25519 signature of transaction's payload data including instructions. This can be used to identify transactions.
```

## Configuring State Commitment

For preflight checks and transaction processing, PUT nodes choose which bank state to query based on a commitment requirement set by the client. The commitment describes how finalized a block is at that point in time. When querying the ledger state, it's recommended to use lower levels of commitment to report progress and higher levels to ensure the state will not be rolled back.

In descending order of commitment (most finalized to least finalized), clients may specify:

```
"finalized" - the node will query the most recent block confirmed by supermajority of the cluster as having reached maximum lockout, meaning the cluster has recognized this block as finalized
"confirmed" - the node will query the most recent block that has been voted on by supermajority of the cluster.
    It incorporates votes from gossip and replay.
    It does not count votes on descendants of a block, only direct votes on that block.
    This confirmation level also upholds "optimistic confirmation" guarantees in release 1.3 and onwards.
"processed" - the node will query its most recent block. Note that the block may still be skipped by the cluster.
```

For processing many dependent transactions in series, it's recommended to use "confirmed" commitment, which balances speed with rollback safety. For total safety, it's recommended to use"finalized" commitment.

Example#

The commitment parameter should be included as the last element in the params array:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getBalance",
    "params": [
      "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri",
      {
        "commitment": "finalized"
      }
    ]
  }
'
```

Default:#

If commitment configuration is not provided, the node will default to "finalized" commitment

Only methods that query bank state accept the commitment parameter. They are indicated in the API Reference below.

RpcResponse Structure#

Many methods that take a commitment parameter return an RpcResponse JSON object comprised of two parts:

```
context : An RpcResponseContext JSON structure including a slot field at which the operation was evaluated.
value : The value returned by the operation itself.
```

Parsed Responses#

Some methods support an encoding parameter, and can return account or instruction data in parsed JSON format if "encoding":"jsonParsed" is requested and the node has a parser for the owning program. PUT nodes currently support JSON parsing for the following native and SPL programs:

```
Program	Account State	Instructions
Address Lookup	v1.14.4	v1.14.4
BPF Loader	n/a	stable
BPF Upgradeable Loader	stable	stable
Config	stable	
SPL Associated Token Account	n/a	stable
SPL Memo	n/a	stable
SPL Token	stable	stable
SPL Token 2022	stable	stable
Stake	stable	stable
Vote	stable	stable
```

The list of account parsers can be found here, and instruction parsers here.

## Health Check

Although not a JSON RPC API, a GET /health at the RPC HTTP Endpoint provides a health-check mechanism for use by load balancers or other network infrastructure. This request will always return a HTTP 200 OK response with a body of "ok", "behind" or "unknown" based on the following conditions:

```
If one or more --known-validator arguments are provided to put-validator, "ok" is returned when the node has within HEALTH_CHECK_SLOT_DISTANCE slots of the highest known validator, otherwise "behind". "unknown" is returned when no slot information from known validators is not yet available.

"ok" is always returned if no known validators are provided.
```

## JSON RPC API Reference\#

### getAccountInfo

Returns all information associated with the account of provided Pubkey

Parameters:#

```
<string> - Pubkey of account to query, as base-58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) encoding: <string> - encoding for Account data, either "base58" (slow), "base64", "base64+zstd", or "jsonParsed". "base58" is limited to Account data of less than 129 bytes. "base64" will return base64 encoded data for Account data of any size. "base64+zstd" compresses the Account data using Zstandard and base64-encodes the result. "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the data field is type <string>.
    (optional) dataSlice: <object> - limit the returned account data using the provided offset: <usize> and length: <usize> fields; only available for "base58", "base64" or "base64+zstd" encodings.
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

The result will be an RpcResponse JSON object with value equal to:

```
<null> - if the requested account doesn't exist
<object> - otherwise, a JSON object containing:
    lamports: <u64>, number of lamports assigned to this account, as a u64
    owner: <string>, base-58 encoded Pubkey of the program this account has been assigned to
    data: <[string, encoding]|object>, data associated with the account, either as encoded binary data or JSON format {<program>: <state>}, depending on encoding parameter
    executable: <bool>, boolean indicating if the account contains a program (and is strictly read-only)
    rentEpoch: <u64>, the epoch at which this account will next owe rent, as u64
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getAccountInfo",
    "params": [
      "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",
      {
        "encoding": "base58"
      }
    ]
  }
'
```

Response:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1
    },
    "value": {
      "data": [
        "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHRTPuR3oZ1EioKtYGiYxpxMG5vpbZLsbcBYBEmZZcMKaSoGx9JZeAuWf",
        "base58"
      ],
      "executable": false,
      "lamports": 1000000000,
      "owner": "11111111111111111111111111111111",
      "rentEpoch": 2
    }
  },
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getAccountInfo",
    "params": [
      "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA",
      {
        "encoding": "jsonParsed"
      }
    ]
  }
'
```

Response:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1
    },
    "value": {
      "data": {
        "nonce": {
          "initialized": {
            "authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX",
            "blockhash": "3xLP3jK6dVJwpeGeTDYTwdDK3TKchUf1gYYGHa4sF3XJ",
            "feeCalculator": {
              "lamportsPerSignature": 5000
            }
          }
        }
      },
      "executable": false,
      "lamports": 1000000000,
      "owner": "11111111111111111111111111111111",
      "rentEpoch": 2
    }
  },
  "id": 1
}
```

### getBalance

Returns the balance of the account of provided Pubkey Parameters:#

```
<string> - Pubkey of account to query, as base-58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

```
RpcResponse<u64> - RpcResponse JSON object with value field set to the balance
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0", "id":1, "method":"getBalance", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": { "context": { "slot": 1 }, "value": 0 },
  "id": 1
}
```

### getBlock

Returns identity and transaction information about a confirmed block in the ledger Parameters:#

```
<u64> - slot, as u64 integer
(optional) <object> - Configuration object containing the following optional fields:
    (optional) encoding: <string> - encoding for each returned Transaction, either "json", "jsonParsed", "base58" (slow), "base64". If parameter not provided, the default encoding is "json". "jsonParsed" encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the transaction.message.instructions list. If "jsonParsed" is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (accounts, data, and programIdIndex fields).
    (optional) transactionDetails: <string> - level of transaction detail to return, either "full", "accounts", "signatures", or "none". If parameter not provided, the default detail level is "full". If "accounts" are requested, transaction details only include signatures and an annotated list of accounts in each transaction. Transaction metadata is limited to only: fee, err, pre_balances, post_balances, pre_token_balances, and post_token_balances.
    (optional) rewards: bool - whether to populate the rewards array. If parameter not provided, the default includes rewards.
    (optional) commitment: <string> - Commitment; "processed" is not supported. If parameter not provided, the default is "finalized".
    (optional) maxSupportedTransactionVersion: <number> - set the max transaction version to return in responses. If the requested block contains a transaction with a higher version, an error will be returned. If this parameter is omitted, only legacy transactions will be returned, and a block containing any versioned transaction will prompt the error.
```

Results:#

The result field will be an object with the following fields:

```
<null> - if specified block is not confirmed
<object> - if block is confirmed, an object with the following fields:
    blockhash: <string> - the blockhash of this block, as base-58 encoded string
    previousBlockhash: <string> - the blockhash of this block's parent, as base-58 encoded string; if the parent block is not available due to ledger cleanup, this field will return "11111111111111111111111111111111"
    parentSlot: <u64> - the slot index of this block's parent
    transactions: <array> - present if "full" transaction details are requested; an array of JSON objects containing:
        transaction: <object|[string,encoding]> - Transaction object, either in JSON format or encoded binary data, depending on encoding parameter
        meta: <object> - transaction status metadata object, containing null or:
            err: <object|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
            fee: <u64> - fee this transaction was charged, as u64 integer
            preBalances: <array> - array of u64 account balances from before the transaction was processed
            postBalances: <array> - array of u64 account balances after the transaction was processed
            innerInstructions: <array|null> - List of inner instructions or null if inner instruction recording was not enabled during this transaction
            preTokenBalances: <array|undefined> - List of token balances from before the transaction was processed or omitted if token balance recording was not yet enabled during this transaction
            postTokenBalances: <array|undefined> - List of token balances from after the transaction was processed or omitted if token balance recording was not yet enabled during this transaction
            logMessages: <array|null> - array of string log messages or null if log message recording was not enabled during this transaction
            rewards: <array|null> - transaction-level rewards, populated if rewards are requested; an array of JSON objects containing:
                pubkey: <string> - The public key, as base-58 encoded string, of the account that received the reward
                lamports: <i64>- number of reward lamports credited or debited by the account, as a i64
                postBalance: <u64> - account balance in lamports after the reward was applied
                rewardType: <string|undefined> - type of reward: "fee", "rent", "voting", "staking"
                commission: <u8|undefined> - vote account commission when the reward was credited, only present for voting and staking rewards
            DEPRECATED: status: <object> - Transaction status
                "Ok": <null> - Transaction was successful
                "Err": <ERR> - Transaction failed with TransactionError
            loadedAddresses: <object|undefined> - Transaction addresses loaded from address lookup tables. Undefined if maxSupportedTransactionVersion is not set in request params.
                writable: <array[string]> - Ordered list of base-58 encoded addresses for writable loaded accounts
                readonly: <array[string]> - Ordered list of base-58 encoded addresses for readonly loaded accounts
            returnData: <object|undefined> - the most-recent return data generated by an instruction in the transaction, with the following fields:
                programId: <string>, the program that generated the return data, as base-58 encoded Pubkey
                data: <[string, encoding]>, the return data itself, as base-64 encoded binary data
            computeUnitsConsumed: <u64|undefined>, number of compute units consumed by the transaction
        version: <"legacy"|number|undefined> - Transaction version. Undefined if maxSupportedTransactionVersion is not set in request params.
    signatures: <array> - present if "signatures" are requested for transaction details; an array of signatures strings, corresponding to the transaction order in the block
    rewards: <array|undefined> - block-level rewards, present if rewards are requested; an array of JSON objects containing:
        pubkey: <string> - The public key, as base-58 encoded string, of the account that received the reward
        lamports: <i64>- number of reward lamports credited or debited by the account, as a i64
        postBalance: <u64> - account balance in lamports after the reward was applied
        rewardType: <string|undefined> - type of reward: "fee", "rent", "voting", "staking"
        commission: <u8|undefined> - vote account commission when the reward was credited, only present for voting and staking rewards
    blockTime: <i64|null> - estimated production time, as Unix timestamp (seconds since the Unix epoch). null if not available
    blockHeight: <u64|null> - the number of blocks beneath this block
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc": "2.0","id":1,"method":"getBlock","params":[430, {"encoding": "json","maxSupportedTransactionVersion":0,"transactionDetails":"full","rewards":false}]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "blockHeight": 428,
    "blockTime": null,
    "blockhash": "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA",
    "parentSlot": 429,
    "previousBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B",
    "transactions": [
      {
        "meta": {
          "err": null,
          "fee": 5000,
          "innerInstructions": [],
          "logMessages": [],
          "postBalances": [499998932500, 26858640, 1, 1, 1],
          "postTokenBalances": [],
          "preBalances": [499998937500, 26858640, 1, 1, 1],
          "preTokenBalances": [],
          "rewards": null,
          "status": {
            "Ok": null
          }
        },
    "transaction": {
      "message": {
        "accountKeys": [
          "3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe",
          "AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc",
          "SysvarS1otHashes111111111111111111111111111",
          "SysvarC1ock11111111111111111111111111111111",
          "Vote111111111111111111111111111111111111111"
        ],
        "header": {
              "numReadonlySignedAccounts": 0,
              "numReadonlyUnsignedAccounts": 3,
              "numRequiredSignatures": 1
            },
            "instructions": [
              {
                "accounts": [1, 2, 3, 0],
                "data": "37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1",
                "programIdIndex": 4
              }
            ],
            "recentBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B"
          },
          "signatures": [
            "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv"
          ]
        }
      }
    ]
  },
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc": "2.0","id":1,"method":"getBlock","params":[430, "base64"]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "blockHeight": 428,
    "blockTime": null,
    "blockhash": "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA",
    "parentSlot": 429,
    "previousBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B",
    "rewards": [],
    "transactions": [
      {
        "meta": {
          "err": null,
          "fee": 5000,
          "innerInstructions": null,
          "logMessages": null,
          "postBalances": [499998932500, 26858640, 1, 1, 1],
          "postTokenBalances": [],
          "preBalances": [499998937500, 26858640, 1, 1, 1],
          "preTokenBalances": [],
          "rewards": [],
          "status": {
            "Ok": null
          }
        },
        "transaction": [
          "AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==",
          "base64"
        ]
      }
    ]
  },
  "id": 1
}
```

Transaction Structure#

Transactions are quite different from those on other blockchains. Be sure to review Anatomy of a Transaction to learn about transactions on PUT.

The JSON structure of a transaction is defined as follows:

```
signatures: <array[string]> - A list of base-58 encoded signatures applied to the transaction. The list is always of length message.header.numRequiredSignatures and not empty. The signature at index i corresponds to the public key at index i in message.accountKeys. The first one is used as the transaction id.
message: <object> - Defines the content of the transaction.
    accountKeys: <array[string]> - List of base-58 encoded public keys used by the transaction, including by the instructions and for signatures. The first message.header.numRequiredSignatures public keys must sign the transaction.
    header: <object> - Details the account types and signatures required by the transaction.
        numRequiredSignatures: <number> - The total number of signatures required to make the transaction valid. The signatures must match the first numRequiredSignatures of message.accountKeys.
        numReadonlySignedAccounts: <number> - The last numReadonlySignedAccounts of the signed keys are read-only accounts. Programs may process multiple transactions that load read-only accounts within a single PoH entry, but are not permitted to credit or debit lamports or modify account data. Transactions targeting the same read-write account are evaluated sequentially.
        numReadonlyUnsignedAccounts: <number> - The last numReadonlyUnsignedAccounts of the unsigned keys are read-only accounts.
    recentBlockhash: <string> - A base-58 encoded hash of a recent block in the ledger used to prevent transaction duplication and to give transactions lifetimes.
    instructions: <array[object]> - List of program instructions that will be executed in sequence and committed in one atomic transaction if all succeed.
        programIdIndex: <number> - Index into the message.accountKeys array indicating the program account that executes this instruction.
        accounts: <array[number]> - List of ordered indices into the message.accountKeys array indicating which accounts to pass to the program.
        data: <string> - The program input data encoded in a base-58 string.
    addressTableLookups: <array[object]|undefined> - List of address table lookups used by a transaction to dynamically load addresses from on-chain address lookup tables. Undefined if maxSupportedTransactionVersion is not set.
        accountKey: <string> - base-58 encoded public key for an address lookup table account.
        writableIndexes: <array[number]> - List of indices used to load addresses of writable accounts from a lookup table.
        readonlyIndexes: <array[number]> - List of indices used to load addresses of readonly accounts from a lookup table.
```

Inner Instructions Structure#

The PUT runtime records the cross-program instructions that are invoked during transaction processing and makes these available for greater transparency of what was executed on-chain per transaction instruction. Invoked instructions are grouped by the originating transaction instruction and are listed in order of processing.

The JSON structure of inner instructions is defined as a list of objects in the following structure:

```
index: number - Index of the transaction instruction from which the inner instruction(s) originated
instructions: <array[object]> - Ordered list of inner program instructions that were invoked during a single transaction instruction.
    programIdIndex: <number> - Index into the message.accountKeys array indicating the program account that executes this instruction.
    accounts: <array[number]> - List of ordered indices into the message.accountKeys array indicating which accounts to pass to the program.
    data: <string> - The program input data encoded in a base-58 string.
```

Token Balances Structure#

The JSON structure of token balances is defined as a list of objects in the following structure:

```
accountIndex: <number> - Index of the account in which the token balance is provided for.
mint: <string> - Pubkey of the token's mint.
owner: <string|undefined> - Pubkey of token balance's owner.
programId: <string|undefined> - Pubkey of the Token program that owns the account.
uiTokenAmount: <object> -
    amount: <string> - Raw amount of tokens as a string, ignoring decimals.
    decimals: <number> - Number of decimals configured for token's mint.
    uiAmount: <number|null> - Token amount as a float, accounting for decimals. DEPRECATED
    uiAmountString: <string> - Token amount as a string, accounting for decimals.
```

### getBlockHeight

Returns the current block height of the node Parameters:#

```
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

```
<u64> - Current block height
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getBlockHeight"}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": 1233, "id": 1 }
```

### getBlockProduction

Returns recent block production information from the current or previous epoch.

Parameters:#

```
(optional) <object> - Configuration object containing the following optional fields:
    (optional) commitment: <string> - Commitment
    (optional) range: <object> - Slot range to return block production for. If parameter not provided, defaults to current epoch.
        firstSlot: <u64> - first slot to return block production information for (inclusive)
        (optional) lastSlot: <u64> - last slot to return block production information for (inclusive). If parameter not provided, defaults to the highest slot
    (optional) identity: <string> - Only return results for this validator identity (base-58 encoded)
```

Results:#

The result will be an RpcResponse JSON object with value equal to:

```
<object>
    byIdentity: <object> - a dictionary of validator identities, as base-58 encoded strings. Value is a two element array containing the number of leader slots and the number of blocks produced.
    range: <object> - Block production slot range
        firstSlot: <u64> - first slot of the block production information (inclusive)
        lastSlot: <u64> - last slot of block production information (inclusive)
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getBlockProduction"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 9887
    },
    "value": {
      "byIdentity": {
        "85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr": [9888, 9886]
      },
      "range": {
        "firstSlot": 0,
        "lastSlot": 9887
      }
    }
  },
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getBlockProduction",
    "params": [
      {
        "identity": "85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr",
        "range": {
          "firstSlot": 40,
          "lastSlot": 50
        }
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 10102
    },
    "value": {
      "byIdentity": {
        "85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr": [11, 11]
      },
      "range": {
        "firstSlot": 50,
        "lastSlot": 40
      }
    }
  },
  "id": 1
}
```

### getBlockCommitment

Returns commitment for particular block Parameters:#

```
<u64> - block, identified by Slot
```

Results:#

The result field will be a JSON object containing:

```
commitment - commitment, comprising either:
    <null> - Unknown block
    <array> - commitment, array of u64 integers logging the amount of cluster stake in lamports that has voted on the block at each depth from 0 to MAX_LOCKOUT_HISTORY + 1
totalStake - total active stake, in lamports, of the current epoch
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getBlockCommitment","params":[5]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "commitment": [
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 10, 32
    ],
    "totalStake": 42
  },
  "id": 1
}
```

### getBlocks

Returns a list of confirmed blocks between two slots

Parameters:#

```
<u64> - start_slot, as u64 integer
(optional) <u64> - end_slot, as u64 integer (must be no more than 500,000 blocks higher than the start_slot)
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment; "processed" is not supported. If parameter not provided, the default is "finalized".
```

Results:#

The result field will be an array of u64 integers listing confirmed blocks between start\_slot and either end\_slot, if provided, or latest confirmed block, inclusive. Max range allowed is 500,000 slots.

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc": "2.0","id":1,"method":"getBlocks","params":[5, 10]}
'
```

Result: { "jsonrpc": "2.0", "result": \[5, 6, 7, 8, 9, 10], "id": 1 }

getBlocksWithLimit#

Returns a list of confirmed blocks starting at the given slot

Parameters:#

```
<u64> - start_slot, as u64 integer
<u64> - limit, as u64 integer (must be no more than 500,000 blocks higher than the start_slot)
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment; "processed" is not supported. If parameter not provided, the default is "finalized".
```

Results:#

The result field will be an array of u64 integers listing confirmed blocks starting at start\_slot for up to limit blocks, inclusive.

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc": "2.0","id":1,"method":"getBlocksWithLimit","params":[5, 3]}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": [5, 6, 7], "id": 1 }
```

### getBlockTime

Returns the estimated production time of a block.

Each validator reports their UTC time to the ledger on a regular interval by intermittently adding a timestamp to a Vote for a particular block. A requested block's time is calculated from the stake-weighted mean of the Vote timestamps in a set of recent blocks recorded on the ledger.

Parameters:#

```
<u64> - block, identified by Slot
```

Results:#

```
<i64> - estimated production time, as Unix timestamp (seconds since the Unix epoch)
<null> - timestamp is not available for this block
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getBlockTime","params":[5]}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": 1574721591, "id": 1 }
```

### getClusterNodes

Returns information about all the nodes participating in the cluster

Parameters:#

None

Results:#

The result field will be an array of JSON objects, each with the following sub fields:

```
pubkey: <string> - Node public key, as base-58 encoded string
gossip: <string|null> - Gossip network address for the node
tpu: <string|null> - TPU network address for the node
rpc: <string|null> - JSON RPC network address for the node, or null if the JSON RPC service is not enabled
version: <string|null> - The software version of the node, or null if the version information is not available
featureSet: <u32|null > - The unique identifier of the node's feature set
shredVersion: <u16|null> - The shred version the node has been configured to use
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0", "id":1, "method":"getClusterNodes"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": [
    {
      "gossip": "10.239.6.48:8001",
      "pubkey": "9QzsJf7LPLj8GkXbYT3LFDKqsj2hHG7TA3xinJHu8epQ",
      "rpc": "10.239.6.48:8899",
      "tpu": "10.239.6.48:8856",
      "version": "1.0.0 c375ce1f"
    }
  ],
  "id": 1
}
```

### getEpochInfo

Returns information about the current epoch

Parameters:#

```
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

The result field will be an object with the following fields:

```
absoluteSlot: <u64>, the current slot
blockHeight: <u64>, the current block height
epoch: <u64>, the current epoch
slotIndex: <u64>, the current slot relative to the start of the current epoch
slotsInEpoch: <u64>, the number of slots in this epoch
transactionCount: <u64|null>, total number of transactions processed without error since genesis
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "absoluteSlot": 166598,
    "blockHeight": 166500,
    "epoch": 27,
    "slotIndex": 2790,
    "slotsInEpoch": 8192,
    "transactionCount": 22661093
  },
  "id": 1
}
```

### getEpochInfo

Returns information about the current epoch

Parameters:#

```
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

The result field will be an object with the following fields:

```
absoluteSlot: <u64>, the current slot
blockHeight: <u64>, the current block height
epoch: <u64>, the current epoch
slotIndex: <u64>, the current slot relative to the start of the current epoch
slotsInEpoch: <u64>, the number of slots in this epoch
transactionCount: <u64|null>, total number of transactions processed without error since genesis
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "absoluteSlot": 166598,
    "blockHeight": 166500,
    "epoch": 27,
    "slotIndex": 2790,
    "slotsInEpoch": 8192,
    "transactionCount": 22661093
  },
  "id": 1
}
```

### getEpochSchedule

Returns epoch schedule information from this cluster's genesis config

Parameters:#

None

Results:#

The result field will be an object with the following fields:

```
slotsPerEpoch: <u64>, the maximum number of slots in each epoch
leaderScheduleSlotOffset: <u64>, the number of slots before beginning of an epoch to calculate a leader schedule for that epoch
warmup: <bool>, whether epochs start short and grow
firstNormalEpoch: <u64>, first normal-length epoch, log2(slotsPerEpoch) - log2(MINIMUM_SLOTS_PER_EPOCH)
firstNormalSlot: <u64>, MINIMUM_SLOTS_PER_EPOCH * (2.pow(firstNormalEpoch) - 1)
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getEpochSchedule"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "firstNormalEpoch": 8,
    "firstNormalSlot": 8160,
    "leaderScheduleSlotOffset": 8192,
    "slotsPerEpoch": 8192,
    "warmup": true
  },
  "id": 1
}
```

### getFeeForMessage

NEW: This method is only available in put-core v1.9 or newer. Please use getFees for put-core v1.8

Get the fee the network will charge for a particular Message

Parameters:#

```
message: <string> - Base-64 encoded Message
(optional) <object> - Configuration object containing the following optional fields:
    (optional) commitment: <string> - Commitment (used for retrieving blockhash)
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

```
<u64|null> - Fee corresponding to the message at the specified blockhash
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
{
  "id":1,
  "jsonrpc":"2.0",
  "method":"getFeeForMessage",
  "params":[
    "AQABAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAA",
    {
      "commitment":"processed"
    }
  ]
}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": { "context": { "slot": 5068 }, "value": 5000 },
  "id": 1
}
```

### getFirstAvailableBlock

Returns the slot of the lowest confirmed block that has not been purged from the ledger

Parameters:#

None

Results:#

```
<u64> - Slot
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getFirstAvailableBlock"}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": 250000, "id": 1 }
```

### getGenesisHash

Returns the genesis hash

Parameters:#

None

Results:#

```
<string> - a Hash as base-58 encoded string
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getGenesisHash"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": "GH7ome3EiwEr7tu9JuTh2dpYWBJK3z69Xm1ZE3MEE6JC",
  "id": 1
}
```

### getHealth

Returns the current health of the node.

If one or more --known-validator arguments are provided to put-validator, "ok" is returned when the node has within HEALTH\_CHECK\_SLOT\_DISTANCE slots of the highest known validator, otherwise an error is returned. "ok" is always returned if no known validators are provided.

Parameters:#

None

Results:#

If the node is healthy: "ok" If the node is unhealthy, a JSON RPC error response is returned. The specifics of the error response are UNSTABLE and may change in the future

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getHealth"}
'
```

Healthy Result:

```
{ "jsonrpc": "2.0", "result": "ok", "id": 1 }
```

Unhealthy Result (generic):

```
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32005,
    "message": "Node is unhealthy",
    "data": {}
  },
  "id": 1
}
```

Unhealthy Result (if additional information is available)

```
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32005,
    "message": "Node is behind by 42 slots",
    "data": {
      "numSlotsBehind": 42
    }
  },
  "id": 1
}
```

### getHighestSnapshotSlot

NEW: This method is only available in put-core v1.9 or newer. Please use getSnapshotSlot for put-core v1.8

Returns the highest slot information that the node has snapshots for.

This will find the highest full snapshot slot, and the highest incremental snapshot slot based on the full snapshot slot, if there is one.

Parameters:#

None

Results:#

```
<object>
    full: <u64> - Highest full snapshot slot
    incremental: <u64|undefined> - Highest incremental snapshot slot based on full
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1,"method":"getHighestSnapshotSlot"}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": { "full": 100, "incremental": 110 }, "id": 1 }
```

Result when the node has no snapshot:

```
{
  "jsonrpc": "2.0",
  "error": { "code": -32008, "message": "No snapshot" },
  "id": 1
}
```

### getIdentity

Returns the identity pubkey for the current node

Parameters:#

None

Results:#

The result field will be a JSON object with the following fields:

```
identity, the identity pubkey of the current node (as a base-58 encoded string)
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getIdentity"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": { "identity": "2r1F4iWqVcb8M1DbAjQuFpebkQHY9hcVU4WuW2DJBppN" },
  "id": 1
}
```

### getInflationGovernor

Returns the current inflation governor

Parameters:#

```
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
```

Results:#

The result field will be a JSON object with the following fields:

```
initial: <f64>, the initial inflation percentage from time 0
terminal: <f64>, terminal inflation percentage
taper: <f64>, rate per year at which inflation is lowered. Rate reduction is derived using the target slot time in genesis config
foundation: <f64>, percentage of total inflation allocated to the foundation
foundationTerm: <f64>, duration of foundation pool inflation in years
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getInflationGovernor"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "foundation": 0.05,
    "foundationTerm": 7,
    "initial": 0.15,
    "taper": 0.15,
    "terminal": 0.015
  },
  "id": 1
}
```

### getInflationRate

Returns the specific inflation values for the current epoch

Parameters:#

None

Results:#

The result field will be a JSON object with the following fields:

```
total: <f64>, total inflation
validator: <f64>, inflation allocated to validators
foundation: <f64>, inflation allocated to the foundation
epoch: <u64>, epoch for which these values are valid
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getInflationRate"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "epoch": 100,
    "foundation": 0.001,
    "total": 0.149,
    "validator": 0.148
  },
  "id": 1
}
```

### getInflationReward

Returns the inflation / staking reward for a list of addresses for an epoch

Parameters:#

```
<array> - An array of addresses to query, as base-58 encoded strings
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) epoch: <u64> - An epoch for which the reward occurs. If omitted, the previous epoch will be used
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results#

The result field will be a JSON array with the following fields:

```
epoch: <u64>, epoch for which reward occured
effectiveSlot: <u64>, the slot in which the rewards are effective
amount: <u64>, reward amount in lamports
postBalance: <u64>, post balance of the account in lamports
commission: <u8|undefined> - vote account commission when the reward was credited
```

Example#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getInflationReward",
    "params": [
       ["6dmNQ5jwLeLk5REvio1JcMshcbvkYMwy26sJ8pbkvStu", "BGsqMegLpV6n6Ve146sSX2dTjUMj3M92HnU8BbNRMhF2"], {"epoch": 2}
    ]
  }
'
```

Response:

```
{
  "jsonrpc": "2.0",
  "result": [
    {
      "amount": 2500,
      "effectiveSlot": 224,
      "epoch": 2,
      "postBalance": 499999442500
    },
    null
  ],
  "id": 1
}
```

### getLargestAccounts

Returns the 20 largest accounts, by lamport balance (results may be cached up to two hours)

Parameters:#

```
(optional) <object> - Configuration object containing the following optional fields:
    (optional) commitment: <string> - Commitment
    (optional) filter: <string> - filter results by account type; currently supported: circulating|nonCirculating
```

Results:#

The result will be an RpcResponse JSON object with value equal to an array of:

```
<object> - otherwise, a JSON object containing:
    address: <string>, base-58 encoded address of the account
    lamports: <u64>, number of lamports in the account, as a u64
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getLargestAccounts"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 54
    },
    "value": [
      {
	"lamports": 999974,
	"address": "99P8ZgtJYe1buSK8JXkvpLh8xPsCFuLYhz9hQFNw93WJ"
      },
      {
	"lamports": 42,
	"address": "uPwWLo16MVehpyWqsLkK3Ka8nLowWvAHbBChqv2FZeL"
      },
      {
	"lamports": 42,
	"address": "aYJCgU7REfu3XF8b3QhkqgqQvLizx8zxuLBHA25PzDS"
      },
      {
	"lamports": 42,
	"address": "CTvHVtQ4gd4gUcw3bdVgZJJqApXE9nCbbbP4VTS5wE1D"
      },
      {
	"lamports": 20,
	"address": "4fq3xJ6kfrh9RkJQsmVd5gNMvJbuSHfErywvEjNQDPxu"
      },
      {
	"lamports": 4,
	"address": "AXJADheGVp9cruP8WYu46oNkRbeASngN5fPCMVGQqNHa"
      },
      {
	"lamports": 2,
	"address": "8NT8yS6LiwNprgW4yM1jPPow7CwRUotddBVkrkWgYp24"
      },
      {
	"lamports": 1,
	"address": "SysvarEpochSchedu1e111111111111111111111111"
      },
      {
	"lamports": 1,
	"address": "11111111111111111111111111111111"
      },
      {
	"lamports": 1,
	"address": "Stake11111111111111111111111111111111111111"
      },
      {
	"lamports": 1,
	"address": "SysvarC1ock11111111111111111111111111111111"
      },
      {
	"lamports": 1,
	"address": "StakeConfig11111111111111111111111111111111"
      },
      {
	"lamports": 1,
	"address": "SysvarRent111111111111111111111111111111111"
      },
      {
	"lamports": 1,
	"address": "Config1111111111111111111111111111111111111"
      },
      {
	"lamports": 1,
	"address": "SysvarStakeHistory1111111111111111111111111"
      },
      {
	"lamports": 1,
	"address": "SysvarRecentB1ockHashes11111111111111111111"
      },
      {
	"lamports": 1,
	"address": "SysvarFees111111111111111111111111111111111"
      },
      {
	"lamports": 1,
	"address": "Vote111111111111111111111111111111111111111"
      }
    ]
  },
  "id": 1
}
```

getLatestBlockhash#

NEW: This method is only available in put-core v1.9 or newer. Please use getRecentBlockhash for put-core v1.8

Returns the latest blockhash Parameters:#

```
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment (used for retrieving blockhash)
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

```
RpcResponse<object> - RpcResponse JSON object with value field set to a JSON object including:
blockhash: <string> - a Hash as base-58 encoded string
lastValidBlockHeight: <u64> - last block height at which the blockhash will be valid
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "id":1,
    "jsonrpc":"2.0",
    "method":"getLatestBlockhash",
    "params":[
      {
	"commitment":"processed"
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 2792
    },
    "value": {
      "blockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N",
      "lastValidBlockHeight": 3090
    }
  },
  "id": 1
}
```

### getLeaderSchedule

Returns the leader schedule for an epoch Parameters:#

```
(optional) <u64> - Fetch the leader schedule for the epoch that corresponds to the provided slot. If unspecified, the leader schedule for the current epoch is fetched
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
    (optional) identity: <string> - Only return results for this validator identity (base-58 encoded)
```

Results:#

```
<null> - if requested epoch is not found
<object> - otherwise, the result field will be a dictionary of validator identities, as base-58 encoded strings, and their corresponding leader slot indices as values (indices are relative to the first slot in the requested epoch)
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F": [
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
      21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
      39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
      57, 58, 59, 60, 61, 62, 63
    ]
  },
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getLeaderSchedule",
    "params": [
      null,
      {
	"identity": "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F"
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F": [
      0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
      21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
      39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
      57, 58, 59, 60, 61, 62, 63
    ]
  },
  "id": 1
}
```

### getMaxRetransmitSlot

Get the max slot seen from retransmit stage.

Results:#

```
<u64> - Slot
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
{"jsonrpc":"2.0","id":1, "method":"getMaxRetransmitSlot"}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": 1234, "id": 1 }
```

### getMaxShredInsertSlot

Get the max slot seen from after shred insert. Results:#

```
<u64> - Slot
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
{"jsonrpc":"2.0","id":1, "method":"getMaxShredInsertSlot"}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": 1234, "id": 1 }
```

### getMinimumBalanceForRentExemption

Returns minimum balance required to make account rent exempt.

Parameters:#

```
<usize> - account data length
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
```

Results:#

```
<u64> - minimum lamports required in account
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
{"jsonrpc":"2.0", "id":1, "method":"getMinimumBalanceForRentExemption", "params":[50]}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": 500, "id": 1 }
```

### getMultipleAccounts

Returns the account information for a list of Pubkeys.

Parameters:#

```
<array> - An array of Pubkeys to query, as base-58 encoded strings (up to a maximum of 100).
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) encoding: <string> - encoding for Account data, either "base58" (slow), "base64", "base64+zstd", or "jsonParsed". "base58" is limited to Account data of less than 129 bytes. "base64" will return base64 encoded data for Account data of any size. "base64+zstd" compresses the Account data using Zstandard and base64-encodes the result. "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the data field is type <string>.
    (optional) dataSlice: <object> - limit the returned account data using the provided offset: <usize> and length: <usize> fields; only available for "base58", "base64" or "base64+zstd" encodings.
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

The result will be an RpcResponse JSON object with value equal to:

An array of:

```
<null> - if the account at that Pubkey doesn't exist
<object> - otherwise, a JSON object containing:
    lamports: <u64>, number of lamports assigned to this account, as a u64
    owner: <string>, base-58 encoded Pubkey of the program this account has been assigned to
    data: <[string, encoding]|object>, data associated with the account, either as encoded binary data or JSON format {<program>: <state>}, depending on encoding parameter
    executable: <bool>, boolean indicating if the account contains a program (and is strictly read-only)
    rentEpoch: <u64>, the epoch at which this account will next owe rent, as u64
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getMultipleAccounts",
    "params": [
      [
        "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",
        "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA"
      ],
      {
        "dataSlice": {
          "offset": 0,
          "length": 0
        }
      }
    ]
  }
```

'

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1
    },
    "value": [
      {
        "data": ["AAAAAAEAAAACtzNsyJrW0g==", "base64"],
        "executable": false,
        "lamports": 1000000000,
        "owner": "11111111111111111111111111111111",
        "rentEpoch": 2
      },
      {
        "data": ["", "base64"],
        "executable": false,
        "lamports": 5000000000,
        "owner": "11111111111111111111111111111111",
        "rentEpoch": 2
      }
    ]
  },
  "id": 1
```

}

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getMultipleAccounts",
    "params": [
      [
        "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",
        "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA"
      ],
      {
        "encoding": "base58"
      }
    ]
  }
```

'

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1
    },
    "value": [
      {
        "data": [
          "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHRTPuR3oZ1EioKtYGiYxpxMG5vpbZLsbcBYBEmZZcMKaSoGx9JZeAuWf",
          "base58"
        ],
        "executable": false,
        "lamports": 1000000000,
        "owner": "11111111111111111111111111111111",
        "rentEpoch": 2
      },
      {
        "data": ["", "base58"],
        "executable": false,
        "lamports": 5000000000,
        "owner": "11111111111111111111111111111111",
        "rentEpoch": 2
      }
    ]
  },
  "id": 1
}
```

### getProgramAccounts

Returns all accounts owned by the provided program Pubkey

Parameters:#

```
<string> - Pubkey of program, as base-58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) encoding: <string> - encoding for Account data, either "base58" (slow), "base64", "base64+zstd", or "jsonParsed". "base58" is limited to Account data of less than 129 bytes. "base64" will return base64 encoded data for Account data of any size. "base64+zstd" compresses the Account data using Zstandard and base64-encodes the result. "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the data field is type <string>.
    (optional) dataSlice: <object> - limit the returned account data using the provided offset: <usize> and length: <usize> fields; only available for "base58", "base64" or "base64+zstd" encodings.
    (optional) filters: <array> - filter results using up to 4 filter objects; account must meet all filter criteria to be included in results
    (optional) withContext: bool - wrap the result in an RpcResponse JSON object.
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Filters:#

```
memcmp: <object> - compares a provided series of bytes with program account data at a particular offset. Fields:
    offset: <usize> - offset into program account data to start comparison
    bytes: <string> - data to match, as encoded string
    encoding: <string> - encoding for filter bytes data, either "base58" or "base64". Data is limited in size to 128 or fewer decoded bytes. NEW: This field, and base64 support generally, is only available in put-core v1.11.2 or newer. Please omit when querying nodes on earlier versions

dataSize: <u64> - compares the program account data length with the provided data size
```

Results:#

By default the result field will be an array of JSON objects. If withContext flag is set the array will be wrapped in an RpcResponse JSON object.

The array will contain:

```
pubkey: <string> - the account Pubkey as base-58 encoded string
account: <object> - a JSON object, with the following sub fields:
    lamports: <u64>, number of lamports assigned to this account, as a u64
    owner: <string>, base-58 encoded Pubkey of the program this account has been assigned to
    data: <[string,encoding]|object>, data associated with the account, either as encoded binary data or JSON format {<program>: <state>}, depending on encoding parameter
    executable: <bool>, boolean indicating if the account contains a program (and is strictly read-only)
    rentEpoch: <u64>, the epoch at which this account will next owe rent, as u64
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0", "id":1, "method":"getProgramAccounts", "params":["4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T"]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": [
    {
      "account": {
        "data": "2R9jLfiAQ9bgdcw6h8s44439",
        "executable": false,
        "lamports": 15298080,
        "owner": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T",
        "rentEpoch": 28
      },
      "pubkey": "CxELquR1gPP8wHe33gZ4QxqGB3sZ9RSwsJ2KshVewkFY"
    }
  ],
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getProgramAccounts",
    "params": [
      "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T",
      {
        "filters": [
          {
            "dataSize": 17
          },
          {
            "memcmp": {
              "offset": 4,
              "bytes": "3Mc6vR"
            }
          }
        ]
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": [
    {
      "account": {
        "data": "2R9jLfiAQ9bgdcw6h8s44439",
        "executable": false,
        "lamports": 15298080,
        "owner": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T",
        "rentEpoch": 28
      },
      "pubkey": "CxELquR1gPP8wHe33gZ4QxqGB3sZ9RSwsJ2KshVewkFY"
    }
  ],
  "id": 1
```

}

### getRecentPerformanceSamples

Returns a list of recent performance samples, in reverse slot order. Performance samples are taken every 60 seconds and include the number of transactions and slots that occur in a given time window.

Parameters:#

```
(optional) limit: <usize> - number of samples to return (maximum 720)
```

Results:#

An array of:

```
RpcPerfSample<object>
    slot: <u64> - Slot in which sample was taken at
    numTransactions: <u64> - Number of transactions in sample
    numSlots: <u64> - Number of slots in sample
    samplePeriodSecs: <u16> - Number of seconds in a sample window
```

Example:#

Request:

```
// Request
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0", "id":1, "method":"getRecentPerformanceSamples", "params": [4]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": [
    {
      "numSlots": 126,
      "numTransactions": 126,
      "samplePeriodSecs": 60,
      "slot": 348125
    },
    {
      "numSlots": 126,
      "numTransactions": 126,
      "samplePeriodSecs": 60,
      "slot": 347999
    },
    {
      "numSlots": 125,
      "numTransactions": 125,
      "samplePeriodSecs": 60,
      "slot": 347873
    },
    {
      "numSlots": 125,
      "numTransactions": 125,
      "samplePeriodSecs": 60,
      "slot": 347748
    }
  ],
  "id": 1
}
```

### getSignaturesForAddress

Returns signatures for confirmed transactions that include the given address in their accountKeys list. Returns signatures backwards in time from the provided signature or most recent confirmed block

Parameters:#

```
<string> - account address as base-58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) limit: <number> - maximum transaction signatures to return (between 1 and 1,000, default: 1,000).
    (optional) before: <string> - start searching backwards from this transaction signature. If not provided the search starts from the top of the highest max confirmed block.
    (optional) until: <string> - search until this transaction signature, if found before limit reached.
    (optional) commitment: <string> - Commitment
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

The result field will be an array of transaction signature information, ordered from newest to oldest transaction:

```
<object>
    signature: <string> - transaction signature as base-58 encoded string
    slot: <u64> - The slot that contains the block with the transaction
    err: <object|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
    memo: <string|null> - Memo associated with the transaction, null if no memo is present
    blockTime: <i64|null> - estimated production time, as Unix timestamp (seconds since the Unix epoch) of when transaction was processed. null if not available.
    confirmationStatus: <string|null> - The transaction's cluster confirmation status; either processed, confirmed, or finalized. See Commitment for more on optimistic confirmation.
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getSignaturesForAddress",
    "params": [
      "Vote111111111111111111111111111111111111111",
      {
        "limit": 1
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": [
    {
      "err": null,
      "memo": null,
      "signature": "5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv",
      "slot": 114,
      "blockTime": null
    }
  ],
  "id": 1
}
```

### getSignatureStatuses

Returns the statuses of a list of signatures. Unless the searchTransactionHistory configuration parameter is included, this method only searches the recent status cache of signatures, which retains statuses for all active slots plus MAX\_RECENT\_BLOCKHASHES rooted slots.

Parameters:#

```
<array> - An array of transaction signatures to confirm, as base-58 encoded strings (up to a maximum of 256)
(optional) <object> - Configuration object containing the following field:
    searchTransactionHistory: <bool> - if true, a PUT node will search its ledger cache for any signatures not found in the recent status cache
```

Results:#

An RpcResponse containing a JSON object consisting of an array of TransactionStatus objects.

```
RpcResponse<object> - RpcResponse JSON object with value field:
```

An array of:

```
<null> - Unknown transaction
<object>
    slot: <u64> - The slot the transaction was processed
    confirmations: <usize|null> - Number of blocks since signature confirmation, null if rooted, as well as finalized by a supermajority of the cluster
    err: <object|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
    confirmationStatus: <string|null> - The transaction's cluster confirmation status; either processed, confirmed, or finalized. See Commitment for more on optimistic confirmation.
    DEPRECATED: status: <object> - Transaction status
        "Ok": <null> - Transaction was successful
        "Err": <ERR> - Transaction failed with TransactionError
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getSignatureStatuses",
    "params": [
      [
        "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
        "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"
      ]
    ]
  }
```

'

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 82
    },
    "value": [
      {
        "slot": 72,
        "confirmations": 10,
        "err": null,
        "status": {
          "Ok": null
        },
        "confirmationStatus": "confirmed"
      },
      null
    ]
  },
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getSignatureStatuses",
    "params": [
      [
        "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"
      ],
      {
        "searchTransactionHistory": true
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 82
    },
    "value": [
      {
        "slot": 48,
        "confirmations": null,
        "err": null,
        "status": {
          "Ok": null
        },
        "confirmationStatus": "finalized"
      },
      null
    ]
  },
  "id": 1
}
```

### getSlot

Returns the slot that has reached the given or default commitment level Parameters:#

```
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

```
<u64> - Current slot
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getSlot"}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": 1234, "id": 1 }
```

### getSlotLeader

Returns the current slot leader

Parameters:#

```
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

```
<string> - Node identity Pubkey as base-58 encoded string
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getSlotLeader"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": "ENvAW7JScgYq6o4zKZwewtkzzJgDzuJAFxYasvmEQdpS",
  "id": 1
}
```

### getSlotLeaders

Returns the slot leaders for a given slot range Parameters:#

```
<u64> - Start slot, as u64 integer
<u64> - Limit, as u64 integer (between 1 and 5,000)
```

Results:#

```
<array[string]> - Node identity public keys as base-58 encoded strings
```

Example:#

If the current slot is #99, query the next 10 leaders with the following request:

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getSlotLeaders", "params":[100, 10]}
'
```

Result:

The first leader returned is the leader for slot #100:

```
{
  "jsonrpc": "2.0",
  "result": [
    "ChorusmmK7i1AxXeiTtQgQZhQNiXYU84ULeaYF1EH15n",
    "ChorusmmK7i1AxXeiTtQgQZhQNiXYU84ULeaYF1EH15n",
    "ChorusmmK7i1AxXeiTtQgQZhQNiXYU84ULeaYF1EH15n",
    "ChorusmmK7i1AxXeiTtQgQZhQNiXYU84ULeaYF1EH15n",
    "Awes4Tr6TX8JDzEhCZY2QVNimT6iD1zWHzf1vNyGvpLM",
    "Awes4Tr6TX8JDzEhCZY2QVNimT6iD1zWHzf1vNyGvpLM",
    "Awes4Tr6TX8JDzEhCZY2QVNimT6iD1zWHzf1vNyGvpLM",
    "Awes4Tr6TX8JDzEhCZY2QVNimT6iD1zWHzf1vNyGvpLM",
    "DWvDTSh3qfn88UoQTEKRV2JnLt5jtJAVoiCo3ivtMwXP",
    "DWvDTSh3qfn88UoQTEKRV2JnLt5jtJAVoiCo3ivtMwXP"
  ],
  "id": 1
}
```

### getStakeActivation

Returns epoch activation information for a stake account

Parameters:#

```
<string> - Pubkey of stake account to query, as base-58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) epoch: <u64> - epoch for which to calculate activation details. If parameter not provided, defaults to current epoch.
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

The result will be a JSON object with the following fields:

```
state: <string - the stake account's activation state, one of: active, inactive, activating, deactivating
active: <u64> - stake active during the epoch
inactive: <u64> - stake inactive during the epoch
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getStakeActivation", "params": ["CYRJWqiSjLitBAcRxPvWpgX3s5TvmN2SuRY3eEYypFvT"]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": { "active": 197717120, "inactive": 0, "state": "active" },
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getStakeActivation",
    "params": [
      "CYRJWqiSjLitBAcRxPvWpgX3s5TvmN2SuRY3eEYypFvT",
      {
        "epoch": 4
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "active": 124429280,
    "inactive": 73287840,
    "state": "activating"
  },
  "id": 1
}
```

### getStakeMinimumDelegation

Returns the stake minimum delegation, in lamports.

Parameters:#

```
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
```

Results:#

The result will be an RpcResponse JSON object with value equal to:

```
<u64> - The stake minimum delegation, in lamports
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1,"method":"getStakeMinimumDelegation"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 501
    },
    "value": 1000000000
  },
  "id": 1
}
```

getSupply#

Returns information about the current supply.

Parameters:#

```
(optional) <object> - Configuration object containing the following optional fields:
    (optional) commitment: <string> - Commitment
    (optional) excludeNonCirculatingAccountsList: <bool> - exclude non circulating accounts list from response
```

Results:#

The result will be an RpcResponse JSON object with value equal to a JSON object containing:

```
total: <u64> - Total supply in lamports
circulating: <u64> - Circulating supply in lamports
nonCirculating: <u64> - Non-circulating supply in lamports
nonCirculatingAccounts: <array> - an array of account addresses of non-circulating accounts, as strings. If excludeNonCirculatingAccountsList is enabled, the returned array will be empty.
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0", "id":1, "method":"getSupply"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1114
    },
    "value": {
      "circulating": 16000,
      "nonCirculating": 1000000,
      "nonCirculatingAccounts": [
        "FEy8pTbP5fEoqMV1GdTz83byuA8EKByqYat1PKDgVAq5",
        "9huDUZfxoJ7wGMTffUE7vh1xePqef7gyrLJu9NApncqA",
        "3mi1GmwEE3zo2jmfDuzvjSX9ovRXsDUKHvsntpkhuLJ9",
        "BYxEJTDerkaRWBem3XgnVcdhppktBXa2HbkHPKj2Ui4Z"
      ],
      "total": 1016000
    }
  },
  "id": 1
}
```

### getTokenAccountBalance

Returns the token balance of an SPL Token account.

Parameters:#

```
<string> - Pubkey of Token account to query, as base-58 encoded string
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
```

Results:#

The result will be an RpcResponse JSON object with value equal to a JSON object containing:

```
amount: <string> - the raw balance without decimals, a string representation of u64
decimals: <u8> - number of base 10 digits to the right of the decimal place
uiAmount: <number|null> - the balance, using mint-prescribed decimals DEPRECATED
uiAmountString: <string> - the balance as a string, using mint-prescribed decimals
```

For more details on returned data: The Token Balances Structure response from getBlock follows a similar structure. Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0", "id":1, "method":"getTokenAccountBalance", "params": ["7fUAJdStEuGbc3sM84cKRL6yYaaSstyLSU4ve5oovLS7"]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1114
    },
    "value": {
      "amount": "9864",
      "decimals": 2,
      "uiAmount": 98.64,
      "uiAmountString": "98.64"
    },
    "id": 1
  }
}
```

### getTokenAccountsByDelegate

Returns all SPL Token accounts by approved Delegate.

Parameters:#

```
<string> - Pubkey of account delegate to query, as base-58 encoded string
<object> - Either:
    mint: <string> - Pubkey of the specific token Mint to limit accounts to, as base-58 encoded string; or
    programId: <string> - Pubkey of the Token program that owns the accounts, as base-58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) encoding: <string> - encoding for Account data, either "base58" (slow), "base64", "base64+zstd", or "jsonParsed". "base58" is limited to Account data of less than 129 bytes. "base64" will return base64 encoded data for Account data of any size. "base64+zstd" compresses the Account data using Zstandard and base64-encodes the result. "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the data field is type <string>.
    (optional) dataSlice: <object> - limit the returned account data using the provided offset: <usize> and length: <usize> fields; only available for "base58", "base64" or "base64+zstd" encodings.
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

The result will be an RpcResponse JSON object with value equal to an array of JSON objects, which will contain:

```
pubkey: <string> - the account Pubkey as base-58 encoded string
account: <object> - a JSON object, with the following sub fields:
    lamports: <u64>, number of lamports assigned to this account, as a u64
    owner: <string>, base-58 encoded Pubkey of the program this account has been assigned to
    data: <object>, Token state data associated with the account, either as encoded binary data or in JSON format {<program>: <state>}
    executable: <bool>, boolean indicating if the account contains a program (and is strictly read-only)
    rentEpoch: <u64>, the epoch at which this account will next owe rent, as u64
```

When the data is requested with the jsonParsed encoding a format similar to that of the Token Balances Structure can be expected inside the structure, both for the tokenAmount and the delegatedAmount, with the latter being an optional object.

Example:#

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTokenAccountsByDelegate",
    "params": [
      "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T",
      {
        "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
      },
      {
        "encoding": "jsonParsed"
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1114
    },
    "value": [
      {
        "account": {
          "data": {
            "program": "spl-token",
            "parsed": {
              "info": {
                "tokenAmount": {
                  "amount": "1",
                  "decimals": 1,
                  "uiAmount": 0.1,
                  "uiAmountString": "0.1"
                },
                "delegate": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T",
                "delegatedAmount": {
                  "amount": "1",
                  "decimals": 1,
                  "uiAmount": 0.1,
                  "uiAmountString": "0.1"
                },
                "state": "initialized",
                "isNative": false,
                "mint": "3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E",
                "owner": "CnPoSPKXu7wJqxe59Fs72tkBeALovhsCxYeFwPCQH9TD"
              },
              "type": "account"
            },
            "space": 165
          },
          "executable": false,
          "lamports": 1726080,
          "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
          "rentEpoch": 4
        },
        "pubkey": "28YTZEwqtMHWrhWcvv34se7pjS7wctgqzCPB3gReCFKp"
      }
    ]
  },
  "id": 1
}
```

getTokenAccountsByOwner#

Returns all SPL Token accounts by token owner.

Parameters:#

```
<string> - Pubkey of account owner to query, as base-58 encoded string
<object> - Either:
    mint: <string> - Pubkey of the specific token Mint to limit accounts to, as base-58 encoded string; or
    programId: <string> - Pubkey of the Token program that owns the accounts, as base-58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) encoding: <string> - encoding for Account data, either "base58" (slow), "base64", "base64+zstd", or "jsonParsed". "base58" is limited to Account data of less than 129 bytes. "base64" will return base64 encoded data for Account data of any size. "base64+zstd" compresses the Account data using Zstandard and base64-encodes the result. "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to "base64" encoding, detectable when the data field is type <string>.
    (optional) dataSlice: <object> - limit the returned account data using the provided offset: <usize> and length: <usize> fields; only available for "base58", "base64" or "base64+zstd" encodings.
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

The result will be an RpcResponse JSON object with value equal to an array of JSON objects, which will contain:

```
pubkey: <string> - the account Pubkey as base-58 encoded string
account: <object> - a JSON object, with the following sub fields:
    lamports: <u64>, number of lamports assigned to this account, as a u64
    owner: <string>, base-58 encoded Pubkey of the program this account has been assigned to
    data: <object>, Token state data associated with the account, either as encoded binary data or in JSON format {<program>: <state>}
    executable: <bool>, boolean indicating if the account contains a program (and is strictly read-only)
    rentEpoch: <u64>, the epoch at which this account will next owe rent, as u64
```

When the data is requested with the jsonParsed encoding a format similar to that of the Token Balances Structure can be expected inside the structure, both for the tokenAmount and the delegatedAmount, with the latter being an optional object.

Example:#

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTokenAccountsByOwner",
    "params": [
      "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F",
      {
        "mint": "3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E"
      },
      {
        "encoding": "jsonParsed"
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1114
    },
    "value": [
      {
        "account": {
          "data": {
            "program": "spl-token",
            "parsed": {
              "accountType": "account",
              "info": {
                "tokenAmount": {
                  "amount": "1",
                  "decimals": 1,
                  "uiAmount": 0.1,
                  "uiAmountString": "0.1"
                },
                "delegate": "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T",
                "delegatedAmount": {
                  "amount": "1",
                  "decimals": 1,
                  "uiAmount": 0.1,
                  "uiAmountString": "0.1"
                },
                "state": "initialized",
                "isNative": false,
                "mint": "3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E",
                "owner": "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F"
              },
              "type": "account"
            },
            "space": 165
          },
          "executable": false,
          "lamports": 1726080,
          "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
          "rentEpoch": 4
        },
        "pubkey": "C2gJg6tKpQs41PRS1nC8aw3ZKNZK3HQQZGVrDFDup5nx"
      }
    ]
  },
  "id": 1
}
```

getTokenLargestAccounts#

Returns the 20 largest accounts of a particular SPL Token type. Parameters:#

```
<string> - Pubkey of token Mint to query, as base-58 encoded string
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
```

Results:#

The result will be an RpcResponse JSON object with value equal to an array of JSON objects containing:

```
address: <string> - the address of the token account
amount: <string> - the raw token account balance without decimals, a string representation of u64
decimals: <u8> - number of base 10 digits to the right of the decimal place
uiAmount: <number|null> - the token account balance, using mint-prescribed decimals DEPRECATED
uiAmountString: <string> - the token account balance as a string, using mint-prescribed decimals
```

Example:#

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0", "id":1, "method":"getTokenLargestAccounts", "params": ["3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E"]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1114
    },
    "value": [
      {
        "address": "FYjHNoFtSQ5uijKrZFyYAxvEr87hsKXkXcxkcmkBAf4r",
        "amount": "771",
        "decimals": 2,
        "uiAmount": 7.71,
        "uiAmountString": "7.71"
      },
      {
        "address": "BnsywxTcaYeNUtzrPxQUvzAWxfzZe3ZLUJ4wMMuLESnu",
        "amount": "229",
        "decimals": 2,
        "uiAmount": 2.29,
        "uiAmountString": "2.29"
      }
    ]
  },
  "id": 1
}
```

### getTokenSupply

Returns the total supply of an SPL Token type.

Parameters:#

```
<string> - Pubkey of token Mint to query, as base-58 encoded string
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
```

Results:#

The result will be an RpcResponse JSON object with value equal to a JSON object containing:

```
amount: <string> - the raw total token supply without decimals, a string representation of u64
decimals: <u8> - number of base 10 digits to the right of the decimal place
uiAmount: <number|null> - the total token supply, using mint-prescribed decimals DEPRECATED
uiAmountString: <string> - the total token supply as a string, using mint-prescribed decimals
```

Example:#

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0", "id":1, "method":"getTokenSupply", "params": ["3wyAj7Rt1TWVPZVteFJPLa26JmLvdb1CAKEFZm3NY75E"]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1114
    },
    "value": {
      "amount": "100000",
      "decimals": 2,
      "uiAmount": 1000,
      "uiAmountString": "1000"
    }
  },
  "id": 1
}
```

### getTransaction

Returns transaction details for a confirmed transaction

Parameters:#

```
<string> - transaction signature as base-58 encoded string
(optional) <object> - Configuration object containing the following optional fields:
    (optional) encoding: <string> - encoding for each returned Transaction, either "json", "jsonParsed", "base58" (slow), "base64". If parameter not provided, the default encoding is "json". "jsonParsed" encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the transaction.message.instructions list. If "jsonParsed" is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (accounts, data, and programIdIndex fields).
    (optional) commitment: <string> - Commitment; "processed" is not supported. If parameter not provided, the default is "finalized".
    (optional) maxSupportedTransactionVersion: <number> - set the max transaction version to return in responses. If the requested transaction is a higher version, an error will be returned. If this parameter is omitted, only legacy transactions will be returned, and any versioned transaction will prompt the error.
```

Results:#

```
<null> - if transaction is not found or not confirmed
<object> - if transaction is confirmed, an object with the following fields:
    slot: <u64> - the slot this transaction was processed in
    transaction: <object|[string,encoding]> - Transaction object, either in JSON format or encoded binary data, depending on encoding parameter
    blockTime: <i64|null> - estimated production time, as Unix timestamp (seconds since the Unix epoch) of when the transaction was processed. null if not available
    meta: <object|null> - transaction status metadata object:
        err: <object|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
        fee: <u64> - fee this transaction was charged, as u64 integer
        preBalances: <array> - array of u64 account balances from before the transaction was processed
        postBalances: <array> - array of u64 account balances after the transaction was processed
        innerInstructions: <array|null> - List of inner instructions or null if inner instruction recording was not enabled during this transaction
        preTokenBalances: <array|undefined> - List of token balances from before the transaction was processed or omitted if token balance recording was not yet enabled during this transaction
        postTokenBalances: <array|undefined> - List of token balances from after the transaction was processed or omitted if token balance recording was not yet enabled during this transaction
        logMessages: <array|null> - array of string log messages or null if log message recording was not enabled during this transaction
        DEPRECATED: status: <object> - Transaction status
            "Ok": <null> - Transaction was successful
            "Err": <ERR> - Transaction failed with TransactionError
        rewards: <array|null> - transaction-level rewards, populated if rewards are requested; an array of JSON objects containing:
            pubkey: <string> - The public key, as base-58 encoded string, of the account that received the reward
            lamports: <i64>- number of reward lamports credited or debited by the account, as a i64
            postBalance: <u64> - account balance in lamports after the reward was applied
            rewardType: <string> - type of reward: currently only "rent", other types may be added in the future
            commission: <u8|undefined> - vote account commission when the reward was credited, only present for voting and staking rewards
        loadedAddresses: <object|undefined> - Transaction addresses loaded from address lookup tables. Undefined if maxSupportedTransactionVersion is not set in request params.
            writable: <array[string]> - Ordered list of base-58 encoded addresses for writable loaded accounts
            readonly: <array[string]> - Ordered list of base-58 encoded addresses for readonly loaded accounts
        returnData: <object|undefined> - the most-recent return data generated by an instruction in the transaction, with the following fields:
            programId: <string>, the program that generated the return data, as base-58 encoded Pubkey
            data: <[string, encoding]>, the return data itself, as base-64 encoded binary data
        computeUnitsConsumed: <u64|undefined>, number of compute units consumed by the transaction
    version: <"legacy"|number|undefined> - Transaction version. Undefined if maxSupportedTransactionVersion is not set in request params.
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTransaction",
    "params": [
      "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv",
      "json"
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "meta": {
      "err": null,
      "fee": 5000,
      "innerInstructions": [],
      "postBalances": [499998932500, 26858640, 1, 1, 1],
      "postTokenBalances": [],
      "preBalances": [499998937500, 26858640, 1, 1, 1],
      "preTokenBalances": [],
      "rewards": [],
      "status": {
        "Ok": null
      }
    },
    "slot": 430,
    "transaction": {
      "message": {
        "accountKeys": [
          "3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe",
          "AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc",
          "SysvarS1otHashes111111111111111111111111111",
          "SysvarC1ock11111111111111111111111111111111",
          "Vote111111111111111111111111111111111111111"
        ],
        "header": {
          "numReadonlySignedAccounts": 0,
          "numReadonlyUnsignedAccounts": 3,
          "numRequiredSignatures": 1
        },
        "instructions": [
          {
            "accounts": [1, 2, 3, 0],
            "data": "37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1",
            "programIdIndex": 4
          }
        ],
        "recentBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B"
      },
      "signatures": [
        "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv"
      ]
    }
  },
  "blockTime": null,
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTransaction",
    "params": [
      "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv",
      "base64"
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "meta": {
      "err": null,
      "fee": 5000,
      "innerInstructions": [],
      "postBalances": [499998932500, 26858640, 1, 1, 1],
      "postTokenBalances": [],
      "preBalances": [499998937500, 26858640, 1, 1, 1],
      "preTokenBalances": [],
      "rewards": null,
      "status": {
        "Ok": null
      }
    },
    "slot": 430,
    "transaction": [
      "AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==",
      "base64"
    ]
  },
  "id": 1
}
```

### getTransactionCount

Returns the current Transaction count from the ledger Parameters:#

```
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

```
<u64> - count
```

Example:#

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getTransactionCount"}
'
```

Result: { "jsonrpc": "2.0", "result": 268, "id": 1 }

getVersion#

Returns the current PUT versions running on the node

Parameters:#

None

Results:#

The result field will be a JSON object with the following fields:

```
put-core, software version of put-core
feature-set, unique identifier of the current software's feature set
```

Example:#

Request: curl <http://localhost:8899> -X POST -H "Content-Type: application/json" -d ' {"jsonrpc":"2.0","id":1, "method":"getVersion"} '

Result: { "jsonrpc": "2.0", "result": { "put-core": "1.14.3" }, "id": 1 }

getVoteAccounts#

Returns the account info and associated stake for all the voting accounts in the current bank.

Parameters:#

```
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
    (optional) votePubkey: <string> - Only return results for this validator vote address (base-58 encoded)
    (optional) keepUnstakedDelinquents: <bool> - Do not filter out delinquent validators with no stake
    (optional) delinquentSlotDistance: <u64> - Specify the number of slots behind the tip that a validator must fall to be considered delinquent. NOTE: For the sake of consistency between ecosystem products, it is not recommended that this argument be specified.
```

Results:#

The result field will be a JSON object of current and delinquent accounts, each containing an array of JSON objects with the following sub fields:

```
votePubkey: <string> - Vote account address, as base-58 encoded string
nodePubkey: <string> - Validator identity, as base-58 encoded string
activatedStake: <u64> - the stake, in lamports, delegated to this vote account and active in this epoch
epochVoteAccount: <bool> - bool, whether the vote account is staked for this epoch
commission: <number>, percentage (0-100) of rewards payout owed to the vote account
lastVote: <u64> - Most recent slot voted on by this vote account
epochCredits: <array> - History of how many credits earned by the end of each epoch, as an array of arrays containing: [epoch, credits, previousCredits]
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getVoteAccounts"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "current": [
      {
        "commission": 0,
        "epochVoteAccount": true,
        "epochCredits": [
          [1, 64, 0],
          [2, 192, 64]
        ],
        "nodePubkey": "B97CCUW3AEZFGy6uUg6zUdnNYvnVq5VG8PUtb2HayTDD",
        "lastVote": 147,
        "activatedStake": 42,
        "votePubkey": "3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw"
      }
    ],
    "delinquent": [
      {
        "commission": 127,
        "epochVoteAccount": false,
        "epochCredits": [],
        "nodePubkey": "6ZPxeQaDo4bkZLRsdNrCzchNQr5LN9QMc9sipXv9Kw8f",
        "lastVote": 0,
        "activatedStake": 0,
        "votePubkey": "CmgCk4aMS7KW1SHX3s9K5tBJ6Yng2LBaC8MFov4wx9sm"
      }
    ]
  },
  "id": 1
}
```

Example: Restrict results to a single validator vote account#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getVoteAccounts",
    "params": [
      {
        "votePubkey": "3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw"
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "current": [
      {
        "commission": 0,
        "epochVoteAccount": true,
        "epochCredits": [
          [1, 64, 0],
          [2, 192, 64]
        ],
        "nodePubkey": "B97CCUW3AEZFGy6uUg6zUdnNYvnVq5VG8PUtb2HayTDD",
        "lastVote": 147,
        "activatedStake": 42,
        "votePubkey": "3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw"
      }
    ],
    "delinquent": []
  },
  "id": 1
}
```

### isBlockhashValid

NEW: This method is only available in put-core v1.9 or newer. Please use getFeeCalculatorForBlockhash for put-core v1.8

Returns whether a blockhash is still valid or not

Parameters:#

```
blockhash: <string> - the blockhash of this block, as base-58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment (used for retrieving blockhash)
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

```
<bool> - True if the blockhash is still valid
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "id":45,
    "jsonrpc":"2.0",
    "method":"isBlockhashValid",
    "params":[
      "J7rBdM6AecPDEZp8aPq5iPSNKVkU5Q76F3oAV4eW5wsW",
      {"commitment":"processed"}
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 2483
    },
    "value": false
  },
  "id": 1
}
```

### minimumLedgerSlot

Returns the lowest slot that the node has information about in its ledger. This value may increase over time if the node is configured to purge older ledger data

Parameters:#

None

Results:#

```
u64 - Minimum ledger slot
```

Example:#

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"minimumLedgerSlot"}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": 1234, "id": 1 }
```

### requestAirdrop

Requests an airdrop of lamports to a Pubkey

Parameters:#

```
<string> - Pubkey of account to receive lamports, as base-58 encoded string
<integer> - lamports, as a u64
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment (used for retrieving blockhash and verifying airdrop success)
```

Results:#

```
<string> - Transaction Signature of airdrop, as base-58 encoded string
```

Example:#

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"requestAirdrop", "params":["83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri", 1000000000]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
  "id": 1
}
```

### sendTransaction

Submits a signed transaction to the cluster for processing.

This method does not alter the transaction in any way; it relays the transaction created by clients to the node as-is.

If the node's rpc service receives the transaction, this method immediately succeeds, without waiting for any confirmations. A successful response from this method does not guarantee the transaction is processed or confirmed by the cluster.

While the rpc service will reasonably retry to submit it, the transaction could be rejected if transaction's recent\_blockhash expires before it lands.

Use getSignatureStatuses to ensure a transaction is processed and confirmed.

Before submitting, the following preflight checks are performed:

```
The transaction signatures are verified
The transaction is simulated against the bank slot specified by the preflight commitment. On failure an error will be returned. Preflight checks may be disabled if desired. It is recommended to specify the same commitment and preflight commitment to avoid confusing behavior.
```

The returned signature is the first signature in the transaction, which is used to identify the transaction (transaction id). This identifier can be easily extracted from the transaction data before submission.

Parameters:#

```
<string> - fully-signed Transaction, as encoded string
(optional) <object> - Configuration object containing the following field:
    skipPreflight: <bool> - if true, skip the preflight transaction checks (default: false)
    (optional) preflightCommitment: <string> - Commitment level to use for preflight (default: "finalized").
    (optional) encoding: <string> - Encoding used for the transaction data. Either "base58" (slow, DEPRECATED), or "base64". (default: "base58").
    (optional) maxRetries: <usize> - Maximum number of times for the RPC node to retry sending the transaction to the leader. If this parameter not provided, the RPC node will retry the transaction until it is finalized or until the blockhash expires.
    (optional) minContextSlot: <number> - set the minimum slot at which to perform preflight transaction checks.
```

Results:#

```
<string> - First Transaction Signature embedded in the transaction, as base-58 encoded string (transaction id)
```

Example:#

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "sendTransaction",
    "params": [
      "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2tAnaAT"
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": "2id3YC2jK9G5Wo2phDx4gJVAew8DcY5NAojnVuao8rkxwPYPe8cSwE5GzhEgJA2y8fVjDEo6iR6ykBvDxrTQrtpb",
  "id": 1
}
```

### simulateTransaction

Simulate sending a transaction

Parameters:#

```
<string> - Transaction, as an encoded string. The transaction must have a valid blockhash, but is not required to be signed.
(optional) <object> - Configuration object containing the following fields:
    sigVerify: <bool> - if true the transaction signatures will be verified (default: false, conflicts with replaceRecentBlockhash)
    (optional) commitment: <string> - Commitment level to simulate the transaction at (default: "finalized").
    (optional) encoding: <string> - Encoding used for the transaction data. Either "base58" (slow, DEPRECATED), or "base64". (default: "base58").
    (optional) replaceRecentBlockhash: <bool> - if true the transaction recent blockhash will be replaced with the most recent blockhash. (default: false, conflicts with sigVerify)
    (optional) accounts: <object> - Accounts configuration object containing the following fields:
        (optional) encoding: <string> - encoding for returned Account data, either "base64" (default), "base64+zstd" or "jsonParsed". "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the data field is type <string>.
        addresses: <array> - An array of accounts to return, as base-58 encoded strings
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

An RpcResponse containing a TransactionStatus object The result will be an RpcResponse JSON object with value set to a JSON object with the following fields:

```
err: <object|string|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
logs: <array|null> - Array of log messages the transaction instructions output during execution, null if simulation failed before the transaction was able to execute (for example due to an invalid blockhash or signature verification failure)
accounts: <array|null> - array of accounts with the same length as the accounts.addresses array in the request
    <null> - if the account doesn't exist or if err is not null
    <object> - otherwise, a JSON object containing:
        lamports: <u64>, number of lamports assigned to this account, as a u64
        owner: <string>, base-58 encoded Pubkey of the program this account has been assigned to
        data: <[string, encoding]|object>, data associated with the account, either as encoded binary data or JSON format {<program>: <state>}, depending on encoding parameter
        executable: <bool>, boolean indicating if the account contains a program (and is strictly read-only)
        rentEpoch: <u64>, the epoch at which this account will next owe rent, as u64
unitsConsumed: <u64|undefined>, The number of compute budget units consumed during the processing of this transaction
returnData: <object|null> - the most-recent return data generated by an instruction in the transaction, with the following fields:
    programId: <string>, the program that generated the return data, as base-58 encoded Pubkey
    data: <[string, encoding]>, the return data itself, as base-64 encoded binary data
```

Example:#

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "simulateTransaction",
    "params": [
      "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAEDArczbMia1tLmq7zz4DinMNN0pJ1JtLdqIJPUw3YrGCzYAMHBsgN27lcgB6H2WQvFgyZuJYHa46puOQo9yQ8CVQbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCp20C7Wj2aiuk5TReAXo+VTVg8QTHjs0UjNMMKCvpzZ+ABAgEBARU=",
      {
        "encoding":"base64",
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 218
    },
    "value": {
      "err": null,
      "accounts": null,
      "logs": [
        "Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri invoke [1]",
        "Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri consumed 2366 of 1400000 compute units",
        "Program return: 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri KgAAAAAAAAA=",
        "Program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success"
      ],
      "returnData": {
        "data": [
          "Kg==",
          "base64"
        ],
        "programId": "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"
      },
      "unitsConsumed": 2366
    }
  },
  "id": 1
}
```

##


# JSON RPC API -2

## Subscription Websocket\#

After connecting to the RPC PubSub websocket at `ws://<ADDRESS>/`:

* Submit subscription requests to the websocket using the methods below
* Multiple subscriptions may be active at once
* Many subscriptions take the optional commitment parameter, defining how finalized a change should be to trigger a notification. For subscriptions, if commitment is unspecified, the default value is "finalized".

accountSubscribe#

Subscribe to an account to receive notifications when the lamports or data for a given account public key changes

Parameters:#

```
<string> - account Pubkey, as base-58 encoded string
(optional) <object> - Configuration object containing the following optional fields:
    (optional) commitment: <string> - Commitment
    encoding: <string> - encoding for Account data, either "base58" (slow), "base64", "base64+zstd" or "jsonParsed". "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the data field is type <string>.
```

Results:#

```
<number> - Subscription id (needed to unsubscribe)
```

Example:#

Request:

```
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "accountSubscribe",
  "params": [
    "CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12",
    {
      "encoding": "base64",
      "commitment": "finalized"
    }
  ]
}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "accountSubscribe",
  "params": [
    "CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12",
    {
      "encoding": "jsonParsed"
    }
  ]
}
```

Result:

```
{ "jsonrpc": "2.0", "result": 23784, "id": 1 }
```

Notification Format:#

The notification format is the same as seen in the getAccountInfo RPC HTTP method.

Base58 encoding:

```
{
  "jsonrpc": "2.0",
  "method": "accountNotification",
  "params": {
    "result": {
      "context": {
        "slot": 5199307
      },
      "value": {
        "data": [
          "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR",
          "base58"
        ],
        "executable": false,
        "lamports": 33594,
        "owner": "11111111111111111111111111111111",
        "rentEpoch": 635
      }
    },
    "subscription": 23784
  }
}
```

Parsed-JSON encoding:

```
{
  "jsonrpc": "2.0",
  "method": "accountNotification",
  "params": {
    "result": {
      "context": {
        "slot": 5199307
      },
      "value": {
        "data": {
          "program": "nonce",
          "parsed": {
            "type": "initialized",
            "info": {
              "authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX",
              "blockhash": "LUaQTmM7WbMRiATdMMHaRGakPtCkc2GHtH57STKXs6k",
              "feeCalculator": {
                "lamportsPerSignature": 5000
              }
            }
          }
        },
        "executable": false,
        "lamports": 33594,
        "owner": "11111111111111111111111111111111",
        "rentEpoch": 635
      }
    },
    "subscription": 23784
  }
}
```

### accountUnsubscribe

Unsubscribe from account change notifications

Parameters:#

```
<number> - id of account Subscription to cancel
```

Results:#

```
<bool> - unsubscribe success message
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "accountUnsubscribe", "params": [0] }
```

Result:

```
{ "jsonrpc": "2.0", "result": true, "id": 1 }
```

### blockSubscribe - Unstable, disabled by default

This subscription is unstable and only available if the validator was started with the --rpc-pubsub-enable-block-subscription flag. The format of this subscription may change in the future

Subscribe to receive notification anytime a new block is Confirmed or Finalized. Parameters:#

```
filter: <string>|<object> - filter criteria for the logs to receive results by account type; currently supported:
    "all" - include all transactions in block
    { "mentionsAccountOrProgram": <string> } - return only transactions that mention the provided public key (as base-58 encoded string). If no mentions in a given block, then no notification will be sent.
(optional) <object> - Configuration object containing the following optional fields:
    (optional) commitment: <string> - Commitment
    (optional) encoding: <string> - encoding for Account data, either "base58" (slow), "base64", "base64+zstd" or "jsonParsed". "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to base64 encoding, detectable when the data field is type <string>. Default is "base64".
    (optional) transactionDetails: <string> - level of transaction detail to return, either "full", "signatures", or "none". If parameter not provided, the default detail level is "full".
    (optional) showRewards: bool - whether to populate the rewards array. If parameter not provided, the default includes rewards.
```

Results:#

```
integer - subscription id (needed to unsubscribe)
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": "1", "method": "blockSubscribe", "params": ["all"] }
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "blockSubscribe",
  "params": [
    {
      "mentionsAccountOrProgram": "LieKvPRE8XeX3Y2xVNHjKlpAScD12lYySBVQ4HqoJ5op"
    },
    {
      "commitment": "confirmed",
      "encoding": "base64",
      "showRewards": true,
      "transactionDetails": "full"
    }
  ]
}
```

Result:

```
{ "jsonrpc": "2.0", "result": 0, "id": 1 }
```

Notification Format:#

The notification will be an object with the following fields:

-slot: - The corresponding slot.

```
err: <object|null> - Error if something went wrong publishing the notification otherwise null.
block: <object|null> - A block object as seen in the getBlock RPC HTTP method.

{
  "jsonrpc": "2.0",
  "method": "blockNotification",
  "params": {
    "result": {
      "context": {
        "slot": 112301554
      },
      "value": {
        "slot": 112301554,
        "block": {
          "previousBlockhash": "GJp125YAN4ufCSUvZJVdCyWQJ7RPWMmwxoyUQySydZA",
          "blockhash": "6ojMHjctdqfB55JDpEpqfHnP96fiaHEcvzEQ2NNcxzHP",
          "parentSlot": 112301553,
          "transactions": [
            {
              "transaction": [
                "OpltwoUvWxYi1P2U8vbIdE/aPntjYo5Aa0VQ2JJyeJE2g9Vvxk8dDGgFMruYfDu8/IfUWb0REppTe7IpAuuLRgIBAAkWnj4KHRpEWWW7gvO1c0BHy06wZi2g7/DLqpEtkRsThAXIdBbhXCLvltw50ZnjDx2hzw74NVn49kmpYj2VZHQJoeJoYJqaKcvuxCi/2i4yywedcVNDWkM84Iuw+cEn9/ROCrXY4qBFI9dveEERQ1c4kdU46xjxj9Vi+QXkb2Kx45QFVkG4Y7HHsoS6WNUiw2m4ffnMNnOVdF9tJht7oeuEfDMuUEaO7l9JeUxppCvrGk3CP45saO51gkwVYEgKzhpKjCx3rgsYxNR81fY4hnUQXSbbc2Y55FkwgRBpVvQK7/+clR4Gjhd3L4y+OtPl7QF93Akg1LaU9wRMs5nvfDFlggqI9PqJl+IvVWrNRdBbPS8LIIhcwbRTkSbqlJQWxYg3Bo2CTVbw7rt1ZubuHWWp0mD/UJpLXGm2JprWTePNULzHu67sfqaWF99LwmwjTyYEkqkRt1T0Je5VzHgJs0N5jY4iIU9K3lMqvrKOIn/2zEMZ+ol2gdgjshx+sphIyhw65F3J/Dbzk04LLkK+CULmN571Y+hFlXF2ke0BIuUG6AUF+4214Cu7FXnqo3rkxEHDZAk0lRrAJ8X/Z+iwuwI5cgbd9uHXZaGT2cvhRs7reawctIXtX1s3kTqM9YV+/wCpDLAp8axcEkaQkLDKRoWxqp8XLNZSKial7Rk+ELAVVKWoWLRXRZ+OIggu0OzMExvVLE5VHqy71FNHq4gGitkiKYNFWSLIE4qGfdFLZXy/6hwS+wq9ewjikCpd//C9BcCL7Wl0iQdUslxNVCBZHnCoPYih9JXvGefOb9WWnjGy14sG9j70+RSVx6BlkFELWwFvIlWR/tHn3EhHAuL0inS2pwX7ZQTAU6gDVaoqbR2EiJ47cKoPycBNvHLoKxoY9AZaBjPl6q8SKQJSFyFd9n44opAgI6zMTjYF/8Ok4VpXEESp3QaoUyTI9sOJ6oFP6f4dwnvQelgXS+AEfAsHsKXxGAIUDQENAgMEBQAGBwgIDg8IBJCER3QXl1AVDBADCQoOAAQLERITDAjb7ugh3gOuTy==",
                "base64"
              ],
              "meta": {
                "err": null,
                "status": {
                  "Ok": null
                },
                "fee": 5000,
                "preBalances": [
                  1758510880, 2067120, 1566000, 1461600, 2039280, 2039280,
                  1900080, 1865280, 0, 3680844220, 2039280
                ],
                "postBalances": [
                  1758505880, 2067120, 1566000, 1461600, 2039280, 2039280,
                  1900080, 1865280, 0, 3680844220, 2039280
                ],
                "innerInstructions": [
                  {
                    "index": 0,
                    "instructions": [
                      {
                        "programIdIndex": 13,
                        "accounts": [1, 15, 3, 4, 2, 14],
                        "data": "21TeLgZXNbtHXVBzCaiRmH"
                      },
                      {
                        "programIdIndex": 14,
                        "accounts": [3, 4, 1],
                        "data": "6qfC8ic7Aq99"
                      },
                      {
                        "programIdIndex": 13,
                        "accounts": [1, 15, 3, 5, 2, 14],
                        "data": "21TeLgZXNbsn4QEpaSEr3q"
                      },
                      {
                        "programIdIndex": 14,
                        "accounts": [3, 5, 1],
                        "data": "6LC7BYyxhFRh"
                      }
                    ]
                  },
                  {
                    "index": 1,
                    "instructions": [
                      {
                        "programIdIndex": 14,
                        "accounts": [4, 3, 0],
                        "data": "7aUiLHFjSVdZ"
                      },
                      {
                        "programIdIndex": 19,
                        "accounts": [17, 18, 16, 9, 11, 12, 14],
                        "data": "8kvZyjATKQWYxaKR1qD53V"
                      },
                      {
                        "programIdIndex": 14,
                        "accounts": [9, 11, 18],
                        "data": "6qfC8ic7Aq99"
                      }
                    ]
                  }
                ],
                "logMessages": [
                  "Program QMNeHCGYnLVDn1icRAfQZpjPLBNkfGbSKRB83G5d8KB invoke [1]",
                  "Program QMWoBmAyJLAsA1Lh9ugMTw2gciTihncciphzdNzdZYV invoke [2]"
                ],
                "preTokenBalances": [
                  {
                    "accountIndex": 4,
                    "mint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u",
                    "uiTokenAmount": {
                      "uiAmount": null,
                      "decimals": 6,
                      "amount": "0",
                      "uiAmountString": "0"
                    },
                    "owner": "LieKvPRE8XeX3Y2xVNHjKlpAScD12lYySBVQ4HqoJ5op",
                    "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
                  },
                  {
                    "accountIndex": 5,
                    "mint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u",
                    "uiTokenAmount": {
                      "uiAmount": 11513.0679,
                      "decimals": 6,
                      "amount": "11513067900",
                      "uiAmountString": "11513.0679"
                    },
                    "owner": "rXhAofQCT7NN9TUqigyEAUzV1uLL4boeD8CRkNBSkYk",
                    "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
                  },
                  {
                    "accountIndex": 10,
                    "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1",
                    "uiTokenAmount": {
                      "uiAmount": null,
                      "decimals": 6,
                      "amount": "0",
                      "uiAmountString": "0"
                    },
                    "owner": "CL9wkGFT3SZRRNa9dgaovuRV7jrVVigBUZ6DjcgySsCU",
                    "programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
                  },
                  {
                    "accountIndex": 11,
                    "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1",
                    "uiTokenAmount": {
                      "uiAmount": 15138.514093,
                      "decimals": 6,
                      "amount": "15138514093",
                      "uiAmountString": "15138.514093"
                    },
                    "owner": "LieKvPRE8XeX3Y2xVNHjKlpAScD12lYySBVQ4HqoJ5op",
                    "programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
                  }
                ],
                "postTokenBalances": [
                  {
                    "accountIndex": 4,
                    "mint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u",
                    "uiTokenAmount": {
                      "uiAmount": null,
                      "decimals": 6,
                      "amount": "0",
                      "uiAmountString": "0"
                    },
                    "owner": "LieKvPRE8XeX3Y2xVNHjKlpAScD12lYySBVQ4HqoJ5op",
                    "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
                  },
                  {
                    "accountIndex": 5,
                    "mint": "iouQcQBAiEXe6cKLS85zmZxUqaCqBdeHFpqKoSz615u",
                    "uiTokenAmount": {
                      "uiAmount": 11513.103028,
                      "decimals": 6,
                      "amount": "11513103028",
                      "uiAmountString": "11513.103028"
                    },
                    "owner": "rXhAofQCT7NN9TUqigyEAUzV1uLL4boeD8CRkNBSkYk",
                    "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
                  },
                  {
                    "accountIndex": 10,
                    "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1",
                    "uiTokenAmount": {
                      "uiAmount": null,
                      "decimals": 6,
                      "amount": "0",
                      "uiAmountString": "0"
                    },
                    "owner": "CL9wkGFT3SZRRNa9dgaovuRV7jrVVigBUZ6DjcgySsCU",
                    "programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
                  },
                  {
                    "accountIndex": 11,
                    "mint": "Saber2gLauYim4Mvftnrasomsv6NvAuncvMEZwcLpD1",
                    "uiTokenAmount": {
                      "uiAmount": 15489.767829,
                      "decimals": 6,
                      "amount": "15489767829",
                      "uiAmountString": "15489.767829"
                    },
                    "owner": "BeiHVPRE8XeX3Y2xVNrSsTpAScH94nYySBVQ4HqgN9at",
                    "programId": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
                  }
                ],
                "rewards": []
              }
            }
          ],
          "blockTime": 1639926816,
          "blockHeight": 101210751
        },
        "err": null
      }
    },
    "subscription": 14
  }
}
```

blockUnsubscribe#

Unsubscribe from block notifications

Parameters:#

```
<integer> - subscription id to cancel
```

Results:#

```
<bool> - unsubscribe success message
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "blockUnsubscribe", "params": [0] }
```

Response:

```
{ "jsonrpc": "2.0", "result": true, "id": 1 }
```

#### logsSubscribe

Subscribe to transaction logging

Parameters:#

```
filter: <string>|<object> - filter criteria for the logs to receive results by account type; currently supported:
    "all" - subscribe to all transactions except for simple vote transactions
    "allWithVotes" - subscribe to all transactions including simple vote transactions
    { "mentions": [ <string> ] } - subscribe to all transactions that mention the provided Pubkey (as base-58 encoded string)
(optional) <object> - Configuration object containing the following optional fields:
    (optional) commitment: <string> - Commitment
```

Results:#

```
<integer> - Subscription id (needed to unsubscribe)
```

Example:#

Request:

```
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "logsSubscribe",
  "params": [
    {
      "mentions": [ "11111111111111111111111111111111" ]
    },
    {
      "commitment": "finalized"
    }
  ]
}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "logsSubscribe",
  "params": [ "all" ]
}
```

Result: { "jsonrpc": "2.0", "result": 24040, "id": 1 }

Notification Format:#

The notification will be an RpcResponse JSON object with value equal to:

```
signature: <string> - The transaction signature base58 encoded.
err: <object|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
logs: <array|null> - Array of log messages the transaction instructions output during execution, null if simulation failed before the transaction was able to execute (for example due to an invalid blockhash or signature verification failure)
```

Example:

```
{
  "jsonrpc": "2.0",
  "method": "logsNotification",
  "params": {
    "result": {
      "context": {
        "slot": 5208469
      },
      "value": {
        "signature": "5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv",
        "err": null,
        "logs": [
          "BPF program 83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri success"
        ]
      }
    },
    "subscription": 24040
  }
}
```

### logsUnsubscribe

Unsubscribe from transaction logging

Parameters:#

```
<integer> - id of subscription to cancel
```

Results:#

```
<bool> - unsubscribe success message
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "logsUnsubscribe", "params": [0] }
```

Result:

```
{ "jsonrpc": "2.0", "result": true, "id": 1 }
```

### programSubscribe

Subscribe to a program to receive notifications when the lamports or data for a given account owned by the program changes

Parameters:#

```
<string> - program_id Pubkey, as base-58 encoded string
(optional) <object> - Configuration object containing the following optional fields:
    (optional) commitment: <string> - Commitment
    encoding: <string> - encoding for Account data, either "base58" (slow), "base64", "base64+zstd" or "jsonParsed". "jsonParsed" encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If "jsonParsed" is requested but a parser cannot be found, the field falls back to base64 encoding, detectable when the data field is type <string>.
    (optional) filters: <array> - filter results using various filter objects; account must meet all filter criteria to be included in results
```

Results:#

```
<integer> - Subscription id (needed to unsubscribe)
```

Example:#

Request:

```
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "programSubscribe",
  "params": [
    "11111111111111111111111111111111",
    {
      "encoding": "base64",
      "commitment": "finalized"
    }
  ]
}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "programSubscribe",
  "params": [
    "11111111111111111111111111111111",
    {
      "encoding": "jsonParsed"
    }
  ]
}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "programSubscribe",
  "params": [
    "11111111111111111111111111111111",
    {
      "encoding": "base64",
      "filters": [
        {
          "dataSize": 80
        }
      ]
    }
  ]
}
```

Result:

```
{ "jsonrpc": "2.0", "result": 24040, "id": 1 }
```

Notification Format:#

The notification format is a single program account object as seen in the getProgramAccounts RPC HTTP method.

Base58 encoding:

```
{
  "jsonrpc": "2.0",
  "method": "programNotification",
  "params": {
    "result": {
      "context": {
        "slot": 5208469
      },
      "value": {
        "pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq",
        "account": {
          "data": [
            "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR",
            "base58"
          ],
          "executable": false,
          "lamports": 33594,
          "owner": "11111111111111111111111111111111",
          "rentEpoch": 636
        }
      }
    },
    "subscription": 24040
  }
}
```

Parsed-JSON encoding:

```
{
  "jsonrpc": "2.0",
  "method": "programNotification",
  "params": {
    "result": {
      "context": {
        "slot": 5208469
      },
      "value": {
        "pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq",
        "account": {
          "data": {
            "program": "nonce",
            "parsed": {
              "type": "initialized",
              "info": {
                "authority": "Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX",
                "blockhash": "LUaQTmM7WbMRiATdMMHaRGakPtCkc2GHtH57STKXs6k",
                "feeCalculator": {
                  "lamportsPerSignature": 5000
                }
              }
            }
          },
          "executable": false,
          "lamports": 33594,
          "owner": "11111111111111111111111111111111",
          "rentEpoch": 636
        }
      }
    },
    "subscription": 24040
  }
}
```

### programUnsubscribe

Unsubscribe from program-owned account change notifications

Parameters:#

```
<integer> - id of account Subscription to cancel
```

Results:#

```
<bool> - unsubscribe success message
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "programUnsubscribe", "params": [0] }
```

Result:

```
{ "jsonrpc": "2.0", "result": true, "id": 1 }
```

### signatureSubscribe

Subscribe to a transaction signature to receive notification when the transaction is confirmed On signatureNotification, the subscription is automatically cancelled

Parameters:#

```
<string> - Transaction Signature, as base-58 encoded string
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
```

Results:#

```
integer - subscription id (needed to unsubscribe)
```

Example:#

Request:

```
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "signatureSubscribe",
  "params": [
    "2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b"
  ]
}

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "signatureSubscribe",
  "params": [
    "2EBVM6cB8vAAD93Ktr6Vd8p67XPbQzCJX47MpReuiCXJAtcjaxpvWpcg9Ege1Nr5Tk3a2GFrByT7WPBjdsTycY9b",
    {
      "commitment": "finalized"
    }
  ]
}
```

Result:

```
{ "jsonrpc": "2.0", "result": 0, "id": 1 }
```

Notification Format:#

The notification will be an RpcResponse JSON object with value containing an object with:

```
err: <object|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
```

Example:

```
{
  "jsonrpc": "2.0",
  "method": "signatureNotification",
  "params": {
    "result": {
      "context": {
        "slot": 5207624
      },
      "value": {
        "err": null
      }
    },
    "subscription": 24006
  }
}
```

### signatureUnsubscribe

Unsubscribe from signature confirmation notification Parameters:#

```
<integer> - subscription id to cancel
```

Results:#

```
<bool> - unsubscribe success message
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "signatureUnsubscribe", "params": [0] }
```

Result:

```
{ "jsonrpc": "2.0", "result": true, "id": 1 }
```

### slotSubscribe

Subscribe to receive notification anytime a slot is processed by the validator

Parameters:#

None

Results:#

```
integer - subscription id (needed to unsubscribe)
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "slotSubscribe" }
```

Result:

```
{ "jsonrpc": "2.0", "result": 0, "id": 1 }
```

Notification Format:#

The notification will be an object with the following fields:

```
parent: <u64> - The parent slot
root: <u64> - The current root slot
slot: <u64> - The newly set slot value
```

Example:

```
{
  "jsonrpc": "2.0",
  "method": "slotNotification",
  "params": {
    "result": {
      "parent": 75,
      "root": 44,
      "slot": 76
    },
    "subscription": 0
  }
}
```

### slotUnsubscribe

Unsubscribe from slot notifications

Parameters:#

```
<integer> - subscription id to cancel
```

Results:#

```
<bool> - unsubscribe success message
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "slotUnsubscribe", "params": [0] }
```

Result:

```
{ "jsonrpc": "2.0", "result": true, "id": 1 }
```

### slotsUpdatesSubscribe - Unstable

This subscription is unstable; the format of this subscription may change in the future and it may not always be supported

Subscribe to receive a notification from the validator on a variety of updates on every slot

Parameters:#

None

Results:#

```
integer - subscription id (needed to unsubscribe)
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "slotsUpdatesSubscribe" }
```

Result: { "jsonrpc": "2.0", "result": 0, "id": 1 }

Notification Format:#

The notification will be an object with the following fields:

```
parent: <u64> - The parent slot
slot: <u64> - The newly updated slot
timestamp: <i64> - The Unix timestamp of the update
type: <string> - The update type, one of:
    "firstShredReceived"
    "completed"
    "createdBank"
    "frozen"
    "dead"
    "optimisticConfirmation"
    "root"

{
  "jsonrpc": "2.0",
  "method": "slotsUpdatesNotification",
  "params": {
    "result": {
      "parent": 75,
      "slot": 76,
      "timestamp": 1625081266243,
      "type": "optimisticConfirmation"
    },
    "subscription": 0
  }
}
```

### slotsUpdatesUnsubscribe

Unsubscribe from slot-update notifications

Parameters:#

```
<integer> - subscription id to cancel
```

Results:#

```
<bool> - unsubscribe success message
```

Example:#

Request:

```
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "slotsUpdatesUnsubscribe",
  "params": [0]
}
```

Result:

```
{ "jsonrpc": "2.0", "result": true, "id": 1 }
```

### rootSubscribe

Subscribe to receive notification anytime a new root is set by the validator.

Parameters:#

None

Results:#

```
integer - subscription id (needed to unsubscribe)
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "rootSubscribe" }
```

Result:

```
{ "jsonrpc": "2.0", "result": 0, "id": 1 }
```

Notification Format:#

The result is the latest root slot number.

```
{
  "jsonrpc": "2.0",
  "method": "rootNotification",
  "params": {
    "result": 42,
    "subscription": 0
  }
}
```

#### rootUnsubscribe

Unsubscribe from root notifications

Parameters:#

```
<integer> - subscription id to cancel
```

Results:#

```
<bool> - unsubscribe success message
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "rootUnsubscribe", "params": [0] }
```

Result:

```
{ "jsonrpc": "2.0", "result": true, "id": 1 }
```

### voteSubscribe - Unstable, disabled by default

This subscription is unstable and only available if the validator was started with the --rpc-pubsub-enable-vote-subscription flag. The format of this subscription may change in the future

Subscribe to receive notification anytime a new vote is observed in gossip. These votes are pre-consensus therefore there is no guarantee these votes will enter the ledger.

Parameters:#

None

Results:#

```
integer - subscription id (needed to unsubscribe)
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "voteSubscribe" }
```

Result:

```
{ "jsonrpc": "2.0", "result": 0, "id": 1 }
```

Notification Format:#

The notification will be an object with the following fields:

```
hash: <string> - The vote hash
slots: <array> - The slots covered by the vote, as an array of u64 integers
timestamp: <i64|null> - The timestamp of the vote
signature: <string> - The signature of the transaction that contained this vote

{
  "jsonrpc": "2.0",
  "method": "voteNotification",
  "params": {
    "result": {
      "hash": "8Rshv2oMkPu5E4opXTRyuyBeZBqQ4S477VG26wUTFxUM",
      "slots": [1, 2],
      "timestamp": null
    },
    "subscription": 0
  }
}
```

### voteUnsubscribe

Unsubscribe from vote notifications

Parameters:#

```
<integer> - subscription id to cancel
```

Results:#

```
<bool> - unsubscribe success message
```

Example:#

Request:

```
{ "jsonrpc": "2.0", "id": 1, "method": "voteUnsubscribe", "params": [0] }
```

Response:

```
{ "jsonrpc": "2.0", "result": true, "id": 1 }
```


# JSON RPC API -3

## JSON RPC API Deprecated Methods

### getConfirmedBlock

DEPRECATED: Please use getBlock instead This method is expected to be removed in put-core v2.0

Returns identity and transaction information about a confirmed block in the ledger

Parameters:#

```
<u64> - slot, as u64 integer
(optional) <object> - Configuration object containing the following optional fields:
    (optional) encoding: <string> - encoding for each returned Transaction, either "json", "jsonParsed", "base58" (slow), "base64". If parameter not provided, the default encoding is "json". "jsonParsed" encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the transaction.message.instructions list. If "jsonParsed" is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (accounts, data, and programIdIndex fields).
    (optional) transactionDetails: <string> - level of transaction detail to return, either "full", "signatures", or "none". If parameter not provided, the default detail level is "full".
    (optional) rewards: bool - whether to populate the rewards array. If parameter not provided, the default includes rewards.
    (optional) commitment: <string> - Commitment; "processed" is not supported. If parameter not provided, the default is "finalized".
```

Results:#

The result field will be an object with the following fields:

```
<null> - if specified block is not confirmed
<object> - if block is confirmed, an object with the following fields:
    blockhash: <string> - the blockhash of this block, as base-58 encoded string
    previousBlockhash: <string> - the blockhash of this block's parent, as base-58 encoded string; if the parent block is not available due to ledger cleanup, this field will return "11111111111111111111111111111111"
    parentSlot: <u64> - the slot index of this block's parent
    transactions: <array> - present if "full" transaction details are requested; an array of JSON objects containing:
        transaction: <object|[string,encoding]> - Transaction object, either in JSON format or encoded binary data, depending on encoding parameter
        meta: <object> - transaction status metadata object, containing null or:
            err: <object|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
            fee: <u64> - fee this transaction was charged, as u64 integer
            preBalances: <array> - array of u64 account balances from before the transaction was processed
            postBalances: <array> - array of u64 account balances after the transaction was processed
            innerInstructions: <array|null> - List of inner instructions or null if inner instruction recording was not enabled during this transaction
            preTokenBalances: <array|undefined> - List of token balances from before the transaction was processed or omitted if token balance recording was not yet enabled during this transaction
            postTokenBalances: <array|undefined> - List of token balances from after the transaction was processed or omitted if token balance recording was not yet enabled during this transaction
            logMessages: <array|null> - array of string log messages or null if log message recording was not enabled during this transaction
            DEPRECATED: status: <object> - Transaction status
                "Ok": <null> - Transaction was successful
                "Err": <ERR> - Transaction failed with TransactionError
    signatures: <array> - present if "signatures" are requested for transaction details; an array of signatures strings, corresponding to the transaction order in the block
    rewards: <array> - present if rewards are requested; an array of JSON objects containing:
        pubkey: <string> - The public key, as base-58 encoded string, of the account that received the reward
        lamports: <i64>- number of reward lamports credited or debited by the account, as a i64
        postBalance: <u64> - account balance in lamports after the reward was applied
        rewardType: <string|undefined> - type of reward: "fee", "rent", "voting", "staking"
        commission: <u8|undefined> - vote account commission when the reward was credited, only present for voting and staking rewards
    blockTime: <i64|null> - estimated production time, as Unix timestamp (seconds since the Unix epoch). null if not available
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, {"encoding": "json","transactionDetails":"full","rewards":false}]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "blockTime": null,
    "blockhash": "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA",
    "parentSlot": 429,
    "previousBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B",
    "transactions": [
      {
        "meta": {
          "err": null,
          "fee": 5000,
          "innerInstructions": [],
          "logMessages": [],
          "postBalances": [499998932500, 26858640, 1, 1, 1],
          "postTokenBalances": [],
          "preBalances": [499998937500, 26858640, 1, 1, 1],
          "preTokenBalances": [],
          "status": {
            "Ok": null
          }
        },
        "transaction": {
          "message": {
            "accountKeys": [
              "3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe",
              "AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc",
              "SysvarS1otHashes111111111111111111111111111",
              "SysvarC1ock11111111111111111111111111111111",
              "Vote111111111111111111111111111111111111111"
            ],
            "header": {
              "numReadonlySignedAccounts": 0,
              "numReadonlyUnsignedAccounts": 3,
              "numRequiredSignatures": 1
            },
            "instructions": [
              {
                "accounts": [1, 2, 3, 0],
                "data": "37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1",
                "programIdIndex": 4
              }
            ],
            "recentBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B"
          },
          "signatures": [
            "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv"
          ]
        }
      }
    ]
  },
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "base64"]}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "blockTime": null,
    "blockhash": "3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA",
    "parentSlot": 429,
    "previousBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B",
    "rewards": [],
    "transactions": [
      {
        "meta": {
          "err": null,
          "fee": 5000,
          "innerInstructions": [],
          "logMessages": [],
          "postBalances": [499998932500, 26858640, 1, 1, 1],
          "postTokenBalances": [],
          "preBalances": [499998937500, 26858640, 1, 1, 1],
          "preTokenBalances": [],
          "status": {
            "Ok": null
          }
        },
        "transaction": [
          "AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==",
          "base64"
        ]
      }
    ]
  },
  "id": 1
}
```

For more details on returned data: Transaction Structure Inner Instructions Structure Token Balances Structure

### getConfirmedBlocks

DEPRECATED: Please use getBlocks instead This method is expected to be removed in put-core v2.0

Returns a list of confirmed blocks between two slots

Parameters:#

```
<u64> - start_slot, as u64 integer
(optional) <u64> - end_slot, as u64 integer
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment; "processed" is not supported. If parameter not provided, the default is "finalized".
```

Results:#

The result field will be an array of u64 integers listing confirmed blocks between start\_slot and either end\_slot, if provided, or latest confirmed block, inclusive. Max range allowed is 500,000 slots. Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc": "2.0","id":1,"method":"getConfirmedBlocks","params":[5, 10]}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": [5, 6, 7, 8, 9, 10], "id": 1 }
```

### getConfirmedBlocksWithLimit

DEPRECATED: Please use getBlocksWithLimit instead This method is expected to be removed in put-core v2.0

Returns a list of confirmed blocks starting at the given slot

Parameters:#

```
<u64> - start_slot, as u64 integer
<u64> - limit, as u64 integer
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment; "processed" is not supported. If parameter not provided, the default is "finalized".
```

Results:#

The result field will be an array of u64 integers listing confirmed blocks starting at start\_slot for up to limit blocks, inclusive.

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc": "2.0","id":1,"method":"getConfirmedBlocksWithLimit","params":[5, 3]}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": [5, 6, 7], "id": 1 }
```

### getConfirmedSignaturesForAddress2

DEPRECATED: Please use getSignaturesForAddress instead This method is expected to be removed in put-core v2.0

Returns signatures for confirmed transactions that include the given address in their accountKeys list. Returns signatures backwards in time from the provided signature or most recent confirmed block

Parameters:#

```
<string> - account address as base-58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) limit: <number> - maximum transaction signatures to return (between 1 and 1,000, default: 1,000).
    (optional) before: <string> - start searching backwards from this transaction signature. If not provided the search starts from the top of the highest max confirmed block.
    (optional) until: <string> - search until this transaction signature, if found before limit reached.
    (optional) commitment: <string> - Commitment; "processed" is not supported. If parameter not provided, the default is "finalized".
```

Results:#

The result field will be an array of transaction signature information, ordered from newest to oldest transaction:

```
<object>
    signature: <string> - transaction signature as base-58 encoded string
    slot: <u64> - The slot that contains the block with the transaction
    err: <object|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
    memo: <string|null> - Memo associated with the transaction, null if no memo is present
    blockTime: <i64|null> - estimated production time, as Unix timestamp (seconds since the Unix epoch) of when transaction was processed. null if not available.
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getConfirmedSignaturesForAddress2",
    "params": [
      "Vote111111111111111111111111111111111111111",
      {
        "limit": 1
      }
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": [
    {
      "err": null,
      "memo": null,
      "signature": "5h6xBEauJ3PK6SWCZ1PGjBvj8vDdWG3KpwATGy1ARAXFSDwt8GFXM7W5Ncn16wmqokgpiKRLuS83KUxyZyv2sUYv",
      "slot": 114,
      "blockTime": null
    }
  ],
  "id": 1
}
```

#### getConfirmedTransaction

DEPRECATED: Please use getTransaction instead This method is expected to be removed in put-core v2.0

Returns transaction details for a confirmed transaction Parameters:#

```
<string> - transaction signature as base-58 encoded string
(optional) <object> - Configuration object containing the following optional fields:
    (optional) encoding: <string> - encoding for each returned Transaction, either "json", "jsonParsed", "base58" (slow), "base64". If parameter not provided, the default encoding is "json". "jsonParsed" encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the transaction.message.instructions list. If "jsonParsed" is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (accounts, data, and programIdIndex fields).
    (optional) commitment: <string> - Commitment; "processed" is not supported. If parameter not provided, the default is "finalized".
```

Results:#

```
<null> - if transaction is not found or not confirmed
<object> - if transaction is confirmed, an object with the following fields:
    slot: <u64> - the slot this transaction was processed in
    transaction: <object|[string,encoding]> - Transaction object, either in JSON format or encoded binary data, depending on encoding parameter
    blockTime: <i64|null> - estimated production time, as Unix timestamp (seconds since the Unix epoch) of when the transaction was processed. null if not available
    meta: <object|null> - transaction status metadata object:
        err: <object|null> - Error if transaction failed, null if transaction succeeded. TransactionError definitions
        fee: <u64> - fee this transaction was charged, as u64 integer
        preBalances: <array> - array of u64 account balances from before the transaction was processed
        postBalances: <array> - array of u64 account balances after the transaction was processed
        innerInstructions: <array|null> - List of inner instructions or null if inner instruction recording was not enabled during this transaction
        preTokenBalances: <array|undefined> - List of token balances from before the transaction was processed or omitted if token balance recording was not yet enabled during this transaction
        postTokenBalances: <array|undefined> - List of token balances from after the transaction was processed or omitted if token balance recording was not yet enabled during this transaction
        logMessages: <array|null> - array of string log messages or null if log message recording was not enabled during this transaction
        DEPRECATED: status: <object> - Transaction status
            "Ok": <null> - Transaction was successful
            "Err": <ERR> - Transaction failed with TransactionError
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getConfirmedTransaction",
    "params": [
      "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv",
      "json"
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "meta": {
      "err": null,
      "fee": 5000,
      "innerInstructions": [],
      "postBalances": [499998932500, 26858640, 1, 1, 1],
      "postTokenBalances": [],
      "preBalances": [499998937500, 26858640, 1, 1, 1],
      "preTokenBalances": [],
      "status": {
        "Ok": null
      }
    },
    "slot": 430,
    "transaction": {
      "message": {
        "accountKeys": [
          "3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe",
          "AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc",
          "SysvarS1otHashes111111111111111111111111111",
          "SysvarC1ock11111111111111111111111111111111",
          "Vote111111111111111111111111111111111111111"
        ],
        "header": {
          "numReadonlySignedAccounts": 0,
          "numReadonlyUnsignedAccounts": 3,
          "numRequiredSignatures": 1
        },
        "instructions": [
          {
            "accounts": [1, 2, 3, 0],
            "data": "37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1",
            "programIdIndex": 4
          }
        ],
        "recentBlockhash": "mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B"
      },
      "signatures": [
        "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv"
      ]
    }
  },
  "blockTime": null,
  "id": 1
}
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getConfirmedTransaction",
    "params": [
      "2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv",
      "base64"
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "meta": {
      "err": null,
      "fee": 5000,
      "innerInstructions": [],
      "postBalances": [499998932500, 26858640, 1, 1, 1],
      "postTokenBalances": [],
      "preBalances": [499998937500, 26858640, 1, 1, 1],
      "preTokenBalances": [],
      "status": {
        "Ok": null
      }
    },
    "slot": 430,
    "transaction": [
      "AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==",
      "base64"
    ]
  },
  "id": 1
}
```

####

### getFeeCalculatorForBlockhash

DEPRECATED: Please use isBlockhashValid or getFeeForMessage instead This method is expected to be removed in put-core v2.0

Returns the fee calculator associated with the query blockhash, or null if the blockhash has expired

Parameters:#

```
<string> - query blockhash as a Base58 encoded string
(optional) <object> - Configuration object containing the following fields:
    (optional) commitment: <string> - Commitment
    (optional) minContextSlot: <number> - set the minimum slot that the request can be evaluated at.
```

Results:#

The result will be an RpcResponse JSON object with value equal to:

```
<null> - if the query blockhash has expired
<object> - otherwise, a JSON object containing:
    feeCalculator: <object>, FeeCalculator object describing the cluster fee rate at the queried blockhash
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getFeeCalculatorForBlockhash",
    "params": [
      "GJxqhuxcgfn5Tcj6y3f8X4FeCDd2RQ6SnEMo1AAxrPRZ"
    ]
  }
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 221
    },
    "value": {
      "feeCalculator": {
        "lamportsPerSignature": 5000
      }
    }
  },
  "id": 1
}
```

### getFeeRateGovernor

Returns the fee rate governor information from the root bank

Parameters:#

None Results:#

The result field will be an object with the following fields:

```
burnPercent: <u8>, Percentage of fees collected to be destroyed
maxLamportsPerSignature: <u64>, Largest value lamportsPerSignature can attain for the next slot
minLamportsPerSignature: <u64>, Smallest value lamportsPerSignature can attain for the next slot
targetLamportsPerSignature: <u64>, Desired fee rate for the cluster
targetSignaturesPerSlot: <u64>, Desired signature rate for the cluster
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getFeeRateGovernor"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 54
    },
    "value": {
      "feeRateGovernor": {
        "burnPercent": 50,
        "maxLamportsPerSignature": 100000,
        "minLamportsPerSignature": 5000,
        "targetLamportsPerSignature": 10000,
        "targetSignaturesPerSlot": 20000
      }
    }
  },
  "id": 1
}
```

### getFees

DEPRECATED: Please use getFeeForMessage instead This method is expected to be removed in put-core v2.0

Returns a recent block hash from the ledger, a fee schedule that can be used to compute the cost of submitting a transaction using it, and the last slot in which the blockhash will be valid. Parameters:#

```
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
```

Results:#

The result will be an RpcResponse JSON object with value set to a JSON object with the following fields:

```
blockhash: <string> - a Hash as base-58 encoded string
feeCalculator: <object> - FeeCalculator object, the fee schedule for this block hash
lastValidSlot: <u64> - DEPRECATED - this value is inaccurate and should not be relied upon
lastValidBlockHeight: <u64> - last block height at which the blockhash will be valid
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getFees"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1
    },
    "value": {
      "blockhash": "CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR",
      "feeCalculator": {
        "lamportsPerSignature": 5000
      },
      "lastValidSlot": 297,
      "lastValidBlockHeight": 296
    }
  },
  "id": 1
}
```

### getRecentBlockhash

DEPRECATED: Please use getLatestBlockhash instead This method is expected to be removed in put-core v2.0

Returns a recent block hash from the ledger, and a fee schedule that can be used to compute the cost of submitting a transaction using it. Parameters:#

```
(optional) <object> - Configuration object containing the following field:
    (optional) commitment: <string> - Commitment
```

Results:#

An RpcResponse containing a JSON object consisting of a string blockhash and FeeCalculator JSON object.

```
RpcResponse<object> - RpcResponse JSON object with value field set to a JSON object including:
blockhash: <string> - a Hash as base-58 encoded string
feeCalculator: <object> - FeeCalculator object, the fee schedule for this block hash
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getRecentBlockhash"}
'
```

Result:

```
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 1
    },
    "value": {
      "blockhash": "CSymwgTNX1j3E4qhKfJAUE41nBWEwXufoYryPbkde5RR",
      "feeCalculator": {
        "lamportsPerSignature": 5000
      }
    }
  },
  "id": 1
}
```

### getSnapshotSlot

DEPRECATED: Please use getHighestSnapshotSlot instead This method is expected to be removed in put-core v2.0

Returns the highest slot that the node has a snapshot for

Parameters:#

None

Results:#

```
<u64> - Snapshot slot
```

Example:#

Request:

```
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
  {"jsonrpc":"2.0","id":1, "method":"getSnapshotSlot"}
'
```

Result:

```
{ "jsonrpc": "2.0", "result": 100, "id": 1 }
```

Result when the node has no snapshot:

```
{
  "jsonrpc": "2.0",
  "error": { "code": -32008, "message": "No snapshot" },
  "id": 1
}
```


# Web3 JavaScript API

## What is PUT-Web3.js?

The PUT-Web3.js library aims to provide complete coverage of PUT. The library was built on top of the PUT JSON RPC API.

You can find the full documentation for the @put/web3.js library here.

## Common Terminology

```
Term	Definition
Program	Stateless executable code written to interpret instructions. Programs are capable of performing actions based on the instructions provided.
Instruction	The smallest unit of a program that a client can include in a transaction. Within its processing code, an instruction may contain one or more cross-program invocations.
Transaction	One or more instructions signed by the client using one or more Keypairs and executed atomically with only two possible outcomes: success or failure.
```

For the full list of terms, see PUT terminology

## Getting Started

### Installation

yarn#

```
$ yarn add @put/web3.js
```

npm#

```
$ npm install --save @put/web3.js
```

Bundle#

```
<!-- Development (un-minified) -->
<script src="https://unpkg.com/@put/web3.js@latest/lib/index.iife.js"></script>

<!-- Production (minified) -->
<script src="https://unpkg.com/@put/web3.js@latest/lib/index.iife.min.js"></script>
```

### Usage

Javascript#

```
const putWeb3 = require("@put/web3.js");
console.log(putWeb3);
```

ES6#

```
import * as putWeb3 from "@put/web3.js";
console.log(putWeb3);
```

Browser Bundle#

```
// putWeb3 is provided in the global namespace by the bundle script
console.log(putWeb3);
```

## Quickstart

### Connecting to a Wallet

To allow users to use your dApp or application on PUT, they will need to get access to their Keypair. A Keypair is a private key with a matching public key, used to sign transactions.

There are two ways to obtain a Keypair:

```
Generate a new Keypair
Obtain a Keypair using the secret key
```

You can obtain a new Keypair with the following:

```
const { Keypair } = require("@put/web3.js");

let keypair = Keypair.generate();
```

This will generate a brand new Keypair for a user to fund and use within your application.

You can allow entry of the secretKey using a textbox, and obtain the Keypair with Keypair.fromSecretKey(secretKey).

```
const { Keypair } = require("@put/web3.js");

let secretKey = Uint8Array.from([
  202, 171, 192, 129, 150, 189, 204, 241, 142, 71, 205, 2, 81, 97, 2, 176, 48,
  81, 45, 1, 96, 138, 220, 132, 231, 131, 120, 77, 66, 40, 97, 172, 91, 245, 84,
  221, 157, 190, 9, 145, 176, 130, 25, 43, 72, 107, 190, 229, 75, 88, 191, 136,
  7, 167, 109, 91, 170, 164, 186, 15, 142, 36, 12, 23,
]);

let keypair = Keypair.fromSecretKey(secretKey);
```

Many wallets today allow users to bring their Keypair using a variety of extensions or web wallets. The general recommendation is to use wallets, not Keypairs, to sign transactions. The wallet creates a layer of separation between the dApp and the Keypair, ensuring that the dApp never has access to the secret key. You can find ways to connect to external wallets with the wallet-adapter library.

### Creating and Sending Transactions

To interact with programs on PUT, you create, sign, and send transactions to the network. Transactions are collections of instructions with signatures. The order that instructions exist in a transaction determines the order they are executed.

A transaction in PUT-Web3.js is created using the Transaction object and adding desired messages, addresses, or instructions.

Take the example of a transfer transaction:

```
const {
  Keypair,
  Transaction,
  SystemProgram,
  LAMPORTS_PER_PUT,
} = require("@put/web3.js");

let fromKeypair = Keypair.generate();
let toKeypair = Keypair.generate();
let transaction = new Transaction();

transaction.add(
  SystemProgram.transfer({
    fromPubkey: fromKeypair.publicKey,
    toPubkey: toKeypair.publicKey,
    lamports: LAMPORTS_PER_PUT,
  }),
);
```

The above code achieves creating a transaction ready to be signed and broadcasted to the network. The SystemProgram.transfer instruction was added to the transaction, containing the amount of lamports to send, and the to and from public keys.

All that is left is to sign the transaction with keypair and send it over the network. You can accomplish sending a transaction by using sendAndConfirmTransaction if you wish to alert the user or do something after a transaction is finished, or use sendTransaction if you don't need to wait for the transaction to be confirmed.

```
const {
  sendAndConfirmTransaction,
  clusterApiUrl,
  Connection,
} = require("@put/web3.js");

let keypair = Keypair.generate();
let connection = new Connection(clusterApiUrl("testnet"));

sendAndConfirmTransaction(connection, transaction, [keypair]);
```

The above code takes in a TransactionInstruction using SystemProgram, creates a Transaction, and sends it over the network. You use Connection in order to define which PUT network you are connecting to, namely mainnet-beta, testnet, or devnet.

### Interacting with Custom Programs

The previous section visits sending basic transactions. In PUT everything you do interacts with different programs, including the previous section's transfer transaction. At the time of writing programs on Put are either written in Rust or C.

Let's look at the SystemProgram. The method signature for allocating space in your account on PUT in Rust looks like this:

```
pub fn allocate(
    pubkey: &Pubkey,
    space: u64
) -> Instruction
```

In PUT when you want to interact with a program you must first know all the accounts you will be interacting with.

You must always provide every account that the program will be interacting within the instruction. Not only that, but you must provide whether or not the account is isSigner or isWritable.

In the allocate method above, a single account pubkey is required, as well as an amount of space for allocation. We know that the allocate method writes to the account by allocating space within it, making the pubkey required to be isWritable. isSigner is required when you are designating the account that is running the instruction. In this case, the signer is the account calling to allocate space within itself.

Let's look at how to call this instruction using put-web3.js:

```
let keypair = web3.Keypair.generate();
let payer = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl("testnet"));

let airdropSignature = await connection.requestAirdrop(
  payer.publicKey,
  web3.LAMPORTS_PER_PUT,
);

await connection.confirmTransaction({ signature: airdropSignature });
```

First, we set up the account Keypair and connection so that we have an account to make allocate on the testnet. We also create a payer Keypair and airdrop some sol so we can pay for the allocate transaction.

```
let allocateTransaction = new web3.Transaction({
  feePayer: payer.publicKey,
});
let keys = [{ pubkey: keypair.publicKey, isSigner: true, isWritable: true }];
let params = { space: 100 };
```

We create the transaction allocateTransaction, keys, and params objects. feePayer is an optional field when creating a transaction that specifies who is paying for the transaction, defaulting to the pubkey of the first signer in the transaction. keys represents all accounts that the program's allocate function will interact with. Since the allocate function also required space, we created params to be used later when invoking the allocate function.

```
let allocateStruct = {
  index: 8,
  layout: struct([u32("instruction"), ns64("space")]),
};
```

The above is created using u32 and ns64 from @put/buffer-layout to facilitate the payload creation. The allocate function takes in the parameter space. To interact with the function we must provide the data as a Buffer format. The buffer-layout library helps with allocating the buffer and encoding it correctly for Rust programs on PUT to interpret.

Let's break down this struct.

```
{
  index: 8, /* <-- */
  layout: struct([
    u32('instruction'),
    ns64('space'),
  ])
}
```

index is set to 8 because the function allocate is in the 8th position in the instruction enum for SystemProgram.

```
/* https://github.com/put-labs/put/blob/21bc43ed58c63c827ba4db30426965ef3e807180/sdk/program/src/system_instruction.rs#L142-L305 */
pub enum SystemInstruction {
    /** 0 **/CreateAccount {/**/},
    /** 1 **/Assign {/**/},
    /** 2 **/Transfer {/**/},
    /** 3 **/CreateAccountWithSeed {/**/},
    /** 4 **/AdvanceNonceAccount,
    /** 5 **/WithdrawNonceAccount(u64),
    /** 6 **/InitializeNonceAccount(Pubkey),
    /** 7 **/AuthorizeNonceAccount(Pubkey),
    /** 8 **/Allocate {/**/},
    /** 9 **/AllocateWithSeed {/**/},
    /** 10 **/AssignWithSeed {/**/},
    /** 11 **/TransferWithSeed {/**/},
    /** 12 **/UpgradeNonceAccount,
}
```

Next up is u32('instruction').

```
{
  index: 8,
  layout: struct([
    u32('instruction'), /* <-- */
    ns64('space'),
  ])
}
```

The layout in the allocate struct must always have u32('instruction') first when you are using it to call an instruction.

```
{
  index: 8,
  layout: struct([
    u32('instruction'),
    ns64('space'), /* <-- */
  ])
}
```

ns64('space') is the argument for the allocate function. You can see in the original allocate function in Rust that space was of the type u64. u64 is an unsigned 64bit integer. Javascript by default only provides up to 53bit integers. ns64 comes from @put/buffer-layout to help with type conversions between Rust and Javascript. You can find more type conversions between Rust and Javascript at put-labs/buffer-layout.

```
let data = Buffer.alloc(allocateStruct.layout.span);
let layoutFields = Object.assign({ instruction: allocateStruct.index }, params);
allocateStruct.layout.encode(layoutFields, data);
```

Using the previously created bufferLayout, we can allocate a data buffer. We then assign our params { space: 100 } so that it maps correctly to the layout, and encode it to the data buffer. Now the data is ready to be sent to the program.

```
allocateTransaction.add(
  new web3.TransactionInstruction({
    keys,
    programId: web3.SystemProgram.programId,
    data,
  }),
);

await web3.sendAndConfirmTransaction(connection, allocateTransaction, [
  payer,
  keypair,
]);
```

Finally, we add the transaction instruction with all the account keys, payer, data, and programId and broadcast the transaction to the network.

The full code can be found below.

```
const { struct, u32, ns64 } = require("@put/buffer-layout");
const { Buffer } = require("buffer");
const web3 = require("@put/web3.js");

let keypair = web3.Keypair.generate();
let payer = web3.Keypair.generate();

let connection = new web3.Connection(web3.clusterApiUrl("testnet"));

let airdropSignature = await connection.requestAirdrop(
  payer.publicKey,
  web3.LAMPORTS_PER_PUT,
);

await connection.confirmTransaction({ signature: airdropSignature });

let allocateTransaction = new web3.Transaction({
  feePayer: payer.publicKey,
});
let keys = [{ pubkey: keypair.publicKey, isSigner: true, isWritable: true }];
let params = { space: 100 };

let allocateStruct = {
  index: 8,
  layout: struct([u32("instruction"), ns64("space")]),
};

let data = Buffer.alloc(allocateStruct.layout.span);
let layoutFields = Object.assign({ instruction: allocateStruct.index }, params);
allocateStruct.layout.encode(layoutFields, data);

allocateTransaction.add(
  new web3.TransactionInstruction({
    keys,
    programId: web3.SystemProgram.programId,
    data,
  }),
);

await web3.sendAndConfirmTransaction(connection, allocateTransaction, [
  payer,
  keypair,
]);
```


# Web3 API Reference

## Web3 API Reference Guide

The @put/web3.js library is a package that has coverage over the PUT JSON RPC API.

You can find the full documentation for the @put/web3.js library here.

## General

### Connection

Source Documentation

Connection is used to interact with the PUT JSON RPC. You can use Connection to confirm transactions, get account info, and more.

You create a connection by defining the JSON RPC cluster endpoint and the desired commitment. Once this is complete, you can use this connection object to interact with any of the PUT JSON RPC API.

Example Usage#

```
const web3 = require("@put/web3.js");

let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");

let slot = await connection.getSlot();
console.log(slot);
// 93186439

let blockTime = await connection.getBlockTime(slot);
console.log(blockTime);
// 1630747045

let block = await connection.getBlock(slot);
console.log(block);

/*
{
    blockHeight: null,
    blockTime: 1630747045,
    blockhash: 'AsFv1aV5DGip9YJHHqVjrGg6EKk55xuyxn2HeiN9xQyn',
    parentSlot: 93186438,
    previousBlockhash: '11111111111111111111111111111111',
    rewards: [],
    transactions: []
}
*/

let slotLeader = await connection.getSlotLeader();
console.log(slotLeader);
//49AqLYbpJYc2DrzGUAH1fhWJy62yxBxpLEkfJwjKy2jr
```

The above example shows only a few of the methods on Connection. Please see the source generated docs for the full list.

### Transaction

SourceDocumentation

A transaction is used to interact with programs on the PUT blockchain. These transactions are constructed with TransactionInstructions, containing all the accounts possible to interact with, as well as any needed data or program addresses. Each TransactionInstruction consists of keys, data, and a programId. You can do multiple instructions in a single transaction, interacting with multiple programs at once.

Example Usage#

```
const web3 = require("@put/web3.js");
const nacl = require("tweetnacl");

// Airdrop PUT for paying transactions
let payer = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");

let airdropSignature = await connection.requestAirdrop(
  payer.publicKey,
  web3.LAMPORTS_PER_PUT,
);

await connection.confirmTransaction({ signature: airdropSignature });

let toAccount = web3.Keypair.generate();

// Create Simple Transaction
let transaction = new web3.Transaction();

// Add an instruction to execute
transaction.add(
  web3.SystemProgram.transfer({
    fromPubkey: payer.publicKey,
    toPubkey: toAccount.publicKey,
    lamports: 1000,
  }),
);

// Send and confirm transaction
// Note: feePayer is by default the first signer, or payer, if the parameter is not set
await web3.sendAndConfirmTransaction(connection, transaction, [payer]);

// Alternatively, manually construct the transaction
let recentBlockhash = await connection.getRecentBlockhash();
let manualTransaction = new web3.Transaction({
  recentBlockhash: recentBlockhash.blockhash,
  feePayer: payer.publicKey,
});
manualTransaction.add(
  web3.SystemProgram.transfer({
    fromPubkey: payer.publicKey,
    toPubkey: toAccount.publicKey,
    lamports: 1000,
  }),
);

let transactionBuffer = manualTransaction.serializeMessage();
let signature = nacl.sign.detached(transactionBuffer, payer.secretKey);

manualTransaction.addSignature(payer.publicKey, signature);

let isVerifiedSignature = manualTransaction.verifySignatures();
console.log(`The signatures were verifed: ${isVerifiedSignature}`);

// The signatures were verified: true

let rawTransaction = manualTransaction.serialize();

await web3.sendAndConfirmRawTransaction(connection, rawTransaction);
```

### Keypair

Source Documentation

The keypair is used to create an account with a public key and secret key within PUT. You can either generate, generate from a seed, or create from a secret key.

Example Usage#

```
const { Keypair } = require("@put/web3.js");

let account = Keypair.generate();

console.log(account.publicKey.toBase58());
console.log(account.secretKey);

// 2DVaHtcdTf7cm18Zm9VV8rKK4oSnjmTkKE6MiXe18Qsb
// Uint8Array(64) [
//   152,  43, 116, 211, 207,  41, 220,  33, 193, 168, 118,
//    24, 176,  83, 206, 132,  47, 194,   2, 203, 186, 131,
//   197, 228, 156, 170, 154,  41,  56,  76, 159, 124,  18,
//    14, 247,  32, 210,  51, 102,  41,  43,  21,  12, 170,
//   166, 210, 195, 188,  60, 220, 210,  96, 136, 158,   6,
//   205, 189, 165, 112,  32, 200, 116, 164, 234
// ]

let seed = Uint8Array.from([
  70, 60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100, 70,
  60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100, 70, 60, 102, 100,
]);
let accountFromSeed = Keypair.fromSeed(seed);

console.log(accountFromSeed.publicKey.toBase58());
console.log(accountFromSeed.secretKey);

// 3LDverZtSC9Duw2wyGC1C38atMG49toPNW9jtGJiw9Ar
// Uint8Array(64) [
//    70,  60, 102, 100,  70,  60, 102, 100,  70,  60, 102,
//   100,  70,  60, 102, 100,  70,  60, 102, 100,  70,  60,
//   102, 100,  70,  60, 102, 100,  70,  60, 102, 100,  34,
//   164,   6,  12,   9, 193, 196,  30, 148, 122, 175,  11,
//    28, 243, 209,  82, 240, 184,  30,  31,  56, 223, 236,
//   227,  60,  72, 215,  47, 208, 209, 162,  59
// ]

let accountFromSecret = Keypair.fromSecretKey(account.secretKey);

console.log(accountFromSecret.publicKey.toBase58());
console.log(accountFromSecret.secretKey);

// 2DVaHtcdTf7cm18Zm9VV8rKK4oSnjmTkKE6MiXe18Qsb
// Uint8Array(64) [
//   152,  43, 116, 211, 207,  41, 220,  33, 193, 168, 118,
//    24, 176,  83, 206, 132,  47, 194,   2, 203, 186, 131,
//   197, 228, 156, 170, 154,  41,  56,  76, 159, 124,  18,
//    14, 247,  32, 210,  51, 102,  41,  43,  21,  12, 170,
//   166, 210, 195, 188,  60, 220, 210,  96, 136, 158,   6,
//   205, 189, 165, 112,  32, 200, 116, 164, 234
// ]
```

Using generate generates a random Keypair for use as an account on PUT. Using fromSeed, you can generate a Keypair using a deterministic constructor. fromSecret creates a Keypair from a secret Uint8array. You can see that the publicKey for the generate Keypair and fromSecret Keypair are the same because the secret from the generate Keypair is used in fromSecret.

Warning: Do not use fromSeed unless you are creating a seed with high entropy. Do not share your seed. Treat the seed like you would a private key.

### PublicKey

Source Documentation

PublicKey is used throughout @put/web3.js in transactions, keypairs, and programs. You require publickey when listing each account in a transaction and as a general identifier on PUT.

A PublicKey can be created with a base58 encoded string, buffer, Uint8Array, number, and an array of numbers.

Example Usage#

```
const { Buffer } = require("buffer");
const web3 = require("@put/web3.js");
const crypto = require("crypto");

// Create a PublicKey with a base58 encoded string
let base58publicKey = new web3.PublicKey(
  "5xot9PVkphiX2adznghwrAuxGs2zeWisNSxMW6hU6Hkj",
);
console.log(base58publicKey.toBase58());

// 5xot9PVkphiX2adznghwrAuxGs2zeWisNSxMW6hU6Hkj

// Create a Program Address
let highEntropyBuffer = crypto.randomBytes(31);
let programAddressFromKey = await web3.PublicKey.createProgramAddress(
  [highEntropyBuffer.slice(0, 31)],
  base58publicKey,
);
console.log(`Generated Program Address: ${programAddressFromKey.toBase58()}`);

// Generated Program Address: 3thxPEEz4EDWHNxo1LpEpsAxZryPAHyvNVXJEJWgBgwJ

// Find Program address given a PublicKey
let validProgramAddress = await web3.PublicKey.findProgramAddress(
  [Buffer.from("", "utf8")],
  programAddressFromKey,
);
console.log(`Valid Program Address: ${validProgramAddress}`);

// Valid Program Address: C14Gs3oyeXbASzwUpqSymCKpEyccfEuSe8VRar9vJQRE,253
```

### SystemProgram

SourceDocumentation

The SystemProgram grants the ability to create accounts, allocate account data, assign an account to programs, work with nonce accounts, and transfer lamports. You can use the SystemInstruction class to help with decoding and reading individual instructions

Example Usage#

```
const web3 = require("@put/web3.js");

// Airdrop PUT for paying transactions
let payer = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");

let airdropSignature = await connection.requestAirdrop(
  payer.publicKey,
  web3.LAMPORTS_PER_PUT,
);

await connection.confirmTransaction({ signature: airdropSignature });

// Allocate Account Data
let allocatedAccount = web3.Keypair.generate();
let allocateInstruction = web3.SystemProgram.allocate({
  accountPubkey: allocatedAccount.publicKey,
  space: 100,
});
let transaction = new web3.Transaction().add(allocateInstruction);

await web3.sendAndConfirmTransaction(connection, transaction, [
  payer,
  allocatedAccount,
]);

// Create Nonce Account
let nonceAccount = web3.Keypair.generate();
let minimumAmountForNonceAccount =
  await connection.getMinimumBalanceForRentExemption(web3.NONCE_ACCOUNT_LENGTH);
let createNonceAccountTransaction = new web3.Transaction().add(
  web3.SystemProgram.createNonceAccount({
    fromPubkey: payer.publicKey,
    noncePubkey: nonceAccount.publicKey,
    authorizedPubkey: payer.publicKey,
    lamports: minimumAmountForNonceAccount,
  }),
);

await web3.sendAndConfirmTransaction(
  connection,
  createNonceAccountTransaction,
  [payer, nonceAccount],
);

// Advance nonce - Used to create transactions as an account custodian
let advanceNonceTransaction = new web3.Transaction().add(
  web3.SystemProgram.nonceAdvance({
    noncePubkey: nonceAccount.publicKey,
    authorizedPubkey: payer.publicKey,
  }),
);

await web3.sendAndConfirmTransaction(connection, advanceNonceTransaction, [
  payer,
]);

// Transfer lamports between accounts
let toAccount = web3.Keypair.generate();

let transferTransaction = new web3.Transaction().add(
  web3.SystemProgram.transfer({
    fromPubkey: payer.publicKey,
    toPubkey: toAccount.publicKey,
    lamports: 1000,
  }),
);
await web3.sendAndConfirmTransaction(connection, transferTransaction, [payer]);

// Assign a new account to a program
let programId = web3.Keypair.generate();
let assignedAccount = web3.Keypair.generate();

let assignTransaction = new web3.Transaction().add(
  web3.SystemProgram.assign({
    accountPubkey: assignedAccount.publicKey,
    programId: programId.publicKey,
  }),
);

await web3.sendAndConfirmTransaction(connection, assignTransaction, [
  payer,
  assignedAccount,
]);
```

### Secp256k1Program

Source Documentation

The Secp256k1Program is used to verify Secp256k1 signatures, which are used by both Bitcoin and Ethereum.

Example Usage#

```
const { keccak_256 } = require("js-sha3");
const web3 = require("@put/web3.js");
const secp256k1 = require("secp256k1");

// Create a Ethereum Address from secp256k1
let secp256k1PrivateKey;
do {
  secp256k1PrivateKey = web3.Keypair.generate().secretKey.slice(0, 32);
} while (!secp256k1.privateKeyVerify(secp256k1PrivateKey));

let secp256k1PublicKey = secp256k1
  .publicKeyCreate(secp256k1PrivateKey, false)
  .slice(1);

let ethAddress =
  web3.Secp256k1Program.publicKeyToEthAddress(secp256k1PublicKey);
console.log(`Ethereum Address: 0x${ethAddress.toString("hex")}`);

// Ethereum Address: 0xadbf43eec40694eacf36e34bb5337fba6a2aa8ee

// Fund a keypair to create instructions
let fromPublicKey = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");

let airdropSignature = await connection.requestAirdrop(
  fromPublicKey.publicKey,
  web3.LAMPORTS_PER_PUT,
);

await connection.confirmTransaction({ signature: airdropSignature });

// Sign Message with Ethereum Key
let plaintext = Buffer.from("string address");
let plaintextHash = Buffer.from(keccak_256.update(plaintext).digest());
let { signature, recid: recoveryId } = secp256k1.ecdsaSign(
  plaintextHash,
  secp256k1PrivateKey,
);

// Create transaction to verify the signature
let transaction = new Transaction().add(
  web3.Secp256k1Program.createInstructionWithEthAddress({
    ethAddress: ethAddress.toString("hex"),
    plaintext,
    signature,
    recoveryId,
  }),
);

// Transaction will succeed if the message is verified to be signed by the address
await web3.sendAndConfirmTransaction(connection, transaction, [fromPublicKey]);
```

### Message

Source Documentation

Message is used as another way to construct transactions. You can construct a message using the accounts, header, instructions, and recentBlockhash that are a part of a transaction. A Transaction is a Message plus the list of required signatures required to execute the transaction.

Example Usage#

```
const { Buffer } = require("buffer");
const bs58 = require("bs58");
const web3 = require("@put/web3.js");

let toPublicKey = web3.Keypair.generate().publicKey;
let fromPublicKey = web3.Keypair.generate();

let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");

let airdropSignature = await connection.requestAirdrop(
  fromPublicKey.publicKey,
  web3.LAMPORTS_PER_PUT,
);

await connection.confirmTransaction({ signature: airdropSignature });

let type = web3.SYSTEM_INSTRUCTION_LAYOUTS.Transfer;
let data = Buffer.alloc(type.layout.span);
let layoutFields = Object.assign({ instruction: type.index });
type.layout.encode(layoutFields, data);

let recentBlockhash = await connection.getRecentBlockhash();

let messageParams = {
  accountKeys: [
    fromPublicKey.publicKey.toString(),
    toPublicKey.toString(),
    web3.SystemProgram.programId.toString(),
  ],
  header: {
    numReadonlySignedAccounts: 0,
    numReadonlyUnsignedAccounts: 1,
    numRequiredSignatures: 1,
  },
  instructions: [
    {
      accounts: [0, 1],
      data: bs58.encode(data),
      programIdIndex: 2,
    },
  ],
  recentBlockhash,
};

let message = new web3.Message(messageParams);

let transaction = web3.Transaction.populate(message, [
  fromPublicKey.publicKey.toString(),
]);

await web3.sendAndConfirmTransaction(connection, transaction, [fromPublicKey]);
```

### Struct

SourceDocumentation

The struct class is used to create Rust compatible structs in javascript. This class is only compatible with Borsh encoded Rust structs.

Example Usage#

Struct in Rust:

```
pub struct Fee {
    pub denominator: u64,
    pub numerator: u64,
}
```

Using web3:

```
import BN from "bn.js";
import { Struct } from "@put/web3.js";

export class Fee extends Struct {
  denominator: BN;
  numerator: BN;
}
```

### Enum

Source Documentation

The Enum class is used to represent a Rust compatible Enum in javascript. The enum will just be a string representation if logged but can be properly encoded/decoded when used in conjunction with Struct. This class is only compatible with Borsh encoded Rust enumerations. Example Usage#

Rust:

```
pub enum AccountType {
    Uninitialized,
    StakePool,
    ValidatorList,
}
```

Web3:

```
import { Enum } from "@put/web3.js";

export class AccountType extends Enum {}
```

### NonceAccount

Source Documentation

Normally a transaction is rejected if a transaction's recentBlockhash field is too old. To provide for certain custodial services, Nonce Accounts are used. Transactions which use a recentBlockhash captured on-chain by a Nonce Account do not expire as long at the Nonce Account is not advanced.

You can create a nonce account by first creating a normal account, then using SystemProgram to make the account a Nonce Account.

Example Usage#

```
const web3 = require("@put/web3.js");

// Create connection
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");

// Generate accounts
let account = web3.Keypair.generate();
let nonceAccount = web3.Keypair.generate();

// Fund account
let airdropSignature = await connection.requestAirdrop(
  account.publicKey,
  web3.LAMPORTS_PER_PUT,
);

await connection.confirmTransaction({ signature: airdropSignature });

// Get Minimum amount for rent exemption
let minimumAmount = await connection.getMinimumBalanceForRentExemption(
  web3.NONCE_ACCOUNT_LENGTH,
);

// Form CreateNonceAccount transaction
let transaction = new web3.Transaction().add(
  web3.SystemProgram.createNonceAccount({
    fromPubkey: account.publicKey,
    noncePubkey: nonceAccount.publicKey,
    authorizedPubkey: account.publicKey,
    lamports: minimumAmount,
  }),
);
// Create Nonce Account
await web3.sendAndConfirmTransaction(connection, transaction, [
  account,
  nonceAccount,
]);

let nonceAccountData = await connection.getNonce(
  nonceAccount.publicKey,
  "confirmed",
);

console.log(nonceAccountData);
// NonceAccount {
//   authorizedPubkey: PublicKey {
//     _bn: <BN: 919981a5497e8f85c805547439ae59f607ea625b86b1138ea6e41a68ab8ee038>
//   },
//   nonce: '93zGZbhMmReyz4YHXjt2gHsvu5tjARsyukxD4xnaWaBq',
//   feeCalculator: { lamportsPerSignature: 5000 }
// }

let nonceAccountInfo = await connection.getAccountInfo(
  nonceAccount.publicKey,
  "confirmed",
);

let nonceAccountFromInfo = web3.NonceAccount.fromAccountData(
  nonceAccountInfo.data,
);

console.log(nonceAccountFromInfo);
// NonceAccount {
//   authorizedPubkey: PublicKey {
//     _bn: <BN: 919981a5497e8f85c805547439ae59f607ea625b86b1138ea6e41a68ab8ee038>
//   },
//   nonce: '93zGZbhMmReyz4YHXjt2gHsvu5tjARsyukxD4xnaWaBq',
//   feeCalculator: { lamportsPerSignature: 5000 }
// }
```

The above example shows both how to create a NonceAccount using SystemProgram.createNonceAccount, as well as how to retrieve the NonceAccount from accountInfo. Using the nonce, you can create transactions offline with the nonce in place of the recentBlockhash.

### VoteAccount

SourceDocumentation

Vote account is an object that grants the capability of decoding vote accounts from the native vote account program on the network.

Example Usage#

```
const web3 = require("@put/web3.js");

let voteAccountInfo = await connection.getProgramAccounts(web3.VOTE_PROGRAM_ID);
let voteAccountFromData = web3.VoteAccount.fromAccountData(
  voteAccountInfo[0].account.data,
);
console.log(voteAccountFromData);
/*
VoteAccount {
  nodePubkey: PublicKey {
    _bn: <BN: cf1c635246d4a2ebce7b96bf9f44cacd7feed5552be3c714d8813c46c7e5ec02>
  },
  authorizedWithdrawer: PublicKey {
    _bn: <BN: b76ae0caa56f2b9906a37f1b2d4f8c9d2a74c1420cd9eebe99920b364d5cde54>
  },
  commission: 10,
  rootSlot: 104570885,
  votes: [
    { slot: 104570886, confirmationCount: 31 },
    { slot: 104570887, confirmationCount: 30 },
    { slot: 104570888, confirmationCount: 29 },
    { slot: 104570889, confirmationCount: 28 },
    { slot: 104570890, confirmationCount: 27 },
    { slot: 104570891, confirmationCount: 26 },
    { slot: 104570892, confirmationCount: 25 },
    { slot: 104570893, confirmationCount: 24 },
    { slot: 104570894, confirmationCount: 23 },
    ...
  ],
  authorizedVoters: [ { epoch: 242, authorizedVoter: [PublicKey] } ],
  priorVoters: [
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object], [Object],
      [Object], [Object]
   ],
  epochCredits: [
    { epoch: 179, credits: 33723163, prevCredits: 33431259 },
    { epoch: 180, credits: 34022643, prevCredits: 33723163 },
    { epoch: 181, credits: 34331103, prevCredits: 34022643 },
    { epoch: 182, credits: 34619348, prevCredits: 34331103 },
    { epoch: 183, credits: 34880375, prevCredits: 34619348 },
    { epoch: 184, credits: 35074055, prevCredits: 34880375 },
    { epoch: 185, credits: 35254965, prevCredits: 35074055 },
    { epoch: 186, credits: 35437863, prevCredits: 35254965 },
    { epoch: 187, credits: 35672671, prevCredits: 35437863 },
    { epoch: 188, credits: 35950286, prevCredits: 35672671 },
    { epoch: 189, credits: 36228439, prevCredits: 35950286 },
    ...
  ],
  lastTimestamp: { slot: 104570916, timestamp: 1635730116 }
}
*/
```

## Staking

### StakeProgram

SourceDocumentation

The StakeProgram facilitates staking PUT and delegating them to any validators on the network. You can use StakeProgram to create a stake account, stake some PUT, authorize accounts for withdrawal of your stake, deactivate your stake, and withdraw your funds. The StakeInstruction class is used to decode and read more instructions from transactions calling the StakeProgram

Example Usage#

```
const web3 = require("@put/web3.js");

// Fund a key to create transactions
let fromPublicKey = web3.Keypair.generate();
let connection = new web3.Connection(web3.clusterApiUrl("devnet"), "confirmed");

let airdropSignature = await connection.requestAirdrop(
  fromPublicKey.publicKey,
  web3.LAMPORTS_PER_PUT,
);
await connection.confirmTransaction({ signature: airdropSignature });

// Create Account
let stakeAccount = web3.Keypair.generate();
let authorizedAccount = web3.Keypair.generate();
/* Note: This is the minimum amount for a stake account -- Add additional Lamports for staking
    For example, we add 50 lamports as part of the stake */
let lamportsForStakeAccount =
  (await connection.getMinimumBalanceForRentExemption(
    web3.StakeProgram.space,
  )) + 50;

let createAccountTransaction = web3.StakeProgram.createAccount({
  fromPubkey: fromPublicKey.publicKey,
  authorized: new web3.Authorized(
    authorizedAccount.publicKey,
    authorizedAccount.publicKey,
  ),
  lamports: lamportsForStakeAccount,
  lockup: new web3.Lockup(0, 0, fromPublicKey.publicKey),
  stakePubkey: stakeAccount.publicKey,
});
await web3.sendAndConfirmTransaction(connection, createAccountTransaction, [
  fromPublicKey,
  stakeAccount,
]);

// Check that stake is available
let stakeBalance = await connection.getBalance(stakeAccount.publicKey);
console.log(`Stake balance: ${stakeBalance}`);
// Stake balance: 2282930

// We can verify the state of our stake. This may take some time to become active
let stakeState = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake state: ${stakeState.state}`);
// Stake state: inactive

// To delegate our stake, we get the current vote accounts and choose the first
let voteAccounts = await connection.getVoteAccounts();
let voteAccount = voteAccounts.current.concat(voteAccounts.delinquent)[0];
let votePubkey = new web3.PublicKey(voteAccount.votePubkey);

// We can then delegate our stake to the voteAccount
let delegateTransaction = web3.StakeProgram.delegate({
  stakePubkey: stakeAccount.publicKey,
  authorizedPubkey: authorizedAccount.publicKey,
  votePubkey: votePubkey,
});
await web3.sendAndConfirmTransaction(connection, delegateTransaction, [
  fromPublicKey,
  authorizedAccount,
]);

// To withdraw our funds, we first have to deactivate the stake
let deactivateTransaction = web3.StakeProgram.deactivate({
  stakePubkey: stakeAccount.publicKey,
  authorizedPubkey: authorizedAccount.publicKey,
});
await web3.sendAndConfirmTransaction(connection, deactivateTransaction, [
  fromPublicKey,
  authorizedAccount,
]);

// Once deactivated, we can withdraw our funds
let withdrawTransaction = web3.StakeProgram.withdraw({
  stakePubkey: stakeAccount.publicKey,
  authorizedPubkey: authorizedAccount.publicKey,
  toPubkey: fromPublicKey.publicKey,
  lamports: stakeBalance,
});

await web3.sendAndConfirmTransaction(connection, withdrawTransaction, [
  fromPublicKey,
  authorizedAccount,
]);
```

### Authorized

Source Documentation

Authorized is an object used when creating an authorized account for staking within PUT. You can designate a staker and withdrawer separately, allowing for a different account to withdraw other than the staker.

You can find more usage of the Authorized object under StakeProgram

### Lockup

Source Documentation

Lockup is used in conjunction with the StakeProgram to create an account. The Lockup is used to determine how long the stake will be locked, or unable to be retrieved. If the Lockup is set to 0 for both epoch and the Unix timestamp, the lockup will be disabled for the stake account.

Example Usage#

```
const {
  Authorized,
  Keypair,
  Lockup,
  StakeProgram,
} = require("@put/web3.js");

let account = Keypair.generate();
let stakeAccount = Keypair.generate();
let authorized = new Authorized(account.publicKey, account.publicKey);
let lockup = new Lockup(0, 0, account.publicKey);

let createStakeAccountInstruction = StakeProgram.createAccount({
  fromPubkey: account.publicKey,
  authorized: authorized,
  lamports: 1000,
  lockup: lockup,
  stakePubkey: stakeAccount.publicKey,
});
```

The above code creates a createStakeAccountInstruction to be used when creating an account with the StakeProgram. The Lockup is set to 0 for both the epoch and Unix timestamp, disabling lockup for the account.

See StakeProgram for more.


# Rust API

Rust API

PUT's Rust crates are published to crates.io and can be found on docs.rs with the "put-" prefix.

Some important crates:

* put-program — Imported by programs running on PUT, compiled to BPF. This crate contains many fundamental data types and is re-exported from put-sdk, which cannot be imported from a PUT program.
* put-sdk — The basic off-chain SDK, it re-exports put-program and adds more APIs on top of that. Most PUT programs that do not run on-chain will import this.
* put-client — For interacting with a PUT node via the JSON RPC API.put-cli-config — Loading and saving the PUT CLI configuration file.
* put-clap-utils — Routines for setting up a CLI, using clap, as used by the main PUT CLI. Includes functions for loading all types of signers supported by the CLI.


# Writing Programs


# Overview

Developers can write and deploy their own programs to the PUT blockchain.

The Helloworld example is a good starting place to see how a program is written, built, deployed, and interacted with on-chain.&#x20;

## Berkeley Packet Filter (BPF)

PUT on-chain programs are compiled via the LLVM compiler infrastructure to an Executable and Linkable Format (ELF) containing a variation of the Berkeley Packet Filter (BPF) bytecode.

Because PUT uses the LLVM compiler infrastructure, a program may be written in any programming language that can target the LLVM's BPF backend.&#x20;

PUT currently supports writing programs in Rust.

BPF provides an efficient instruction set that can be executed in an interpreted virtual machine or as efficient just-in-time compiled native instructions.

## Memory map

The virtual address memory map used by PUT BPF programs is fixed and laid out as follows

* Program code starts at 0x100000000
* Stack data starts at 0x200000000
* Heap data starts at 0x300000000
* Program input parameters start at 0x400000000

The above virtual addresses are start addresses but programs are given access to a subset of the memory map.&#x20;

The program will panic if it attempts to read or write to a virtual address that it was not granted access to, and an AccessViolation error will be returned that contains the address and size of the attempted violation.

## Stack

BPF uses stack frames instead of a variable stack pointer. Each stack frame is 4KB in size.

If a program violates that stack frame size, the compiler will report the overrun as a warning.

For example: Error: Function \_ZN16curve25519\_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E Stack offset of -30728 exceeded max offset of -4096 by 26632 bytes, please minimize large stack variables

The message identifies which symbol is exceeding its stack frame but the name might be mangled if it is a Rust or C++ symbol. To demangle a Rust symbol use rustfilt. The above warning came from a Rust program, so the demangled symbol name is:

```
$ rustfilt _ZN16curve25519_dalek7edwards21EdwardsBasepointTable6create17h178b3d2411f7f082E
curve25519_dalek::edwards::EdwardsBasepointTable::create
```

To demangle a C++ symbol use c++filt from binutils.

The reason a warning is reported rather than an error is because some dependent crates may include functionality that violates the stack frame restrictions even if the program doesn't use that functionality.&#x20;

If the program violates the stack size at runtime, an AccessViolation error will be reported.

BPF stack frames occupy a virtual address range starting at 0x200000000.

## Call Depth

Programs are constrained to run quickly, and to facilitate this, the program's call stack is limited to a max depth of 64 frames.&#x20;

## Heap

Programs have access to a runtime heap either directly in C or via the Rust alloc APIs.&#x20;

To facilitate fast allocations, a simple 32KB bump heap is utilized.

&#x20;The heap does not support free or realloc so use it wisely.

Internally, programs have access to the 32KB memory region starting at virtual address 0x300000000 and may implement a custom heap based on the program's specific needs.

* Rust program heap usage

## Float Support

Programs support a limited subset of Rust's float operations, if a program attempts to use a float operation that is not supported, the runtime will report an unresolved symbol error.

Float operations are performed via software libraries, specifically LLVM's float builtins.&#x20;

Due to the software emulated they consume more compute units than integer operations. In general, fixed point operations are recommended where possible.

The PUT Program Library math tests will report the performance of some math operations: <https://github.com/put-labs/put-program-library/tree/master/libraries/math>

To run the test, sync the repo, and run:

$ cargo test-bpf -- --nocapture --test-threads=1

Recent results show the float operations take more instructions compared to integers equivalents.

&#x20;Fixed point implementations may vary but will also be less than the float equivalents:

```
         u64   f32
Multipy    8   176
Divide     9   219
```

## Static Writable Data

Program shared objects do not support writable shared data. Programs are shared between multiple parallel executions using the same shared read-only code and data.&#x20;

This means that developers should not include any static writable or global variables in programs. In the future a copy-on-write mechanism could be added to support writable data.&#x20;

## Signed division

The BPF instruction set does not support signed division. Adding a signed division instruction is a consideration.&#x20;

## Loaders

Programs are deployed with and executed by runtime loaders, currently there are two supported loaders BPF Loader and BPF loader deprecated

Loaders may support different application binary interfaces so developers must write their programs for and deploy them to the same loader.&#x20;

If a program written for one loader is deployed to a different one the result is usually a AccessViolation error due to mismatched deserialization of the program's input parameters.

For all practical purposes program should always be written to target the latest BPF loader and the latest loader is the default for the command-line interface and the javascript APIs.

For language specific information about implementing a program for a particular loader see:

* Rust program entrypoints

### Deployment

BPF program deployment is the process of uploading a BPF shared object into a program account's data and marking the account executable.&#x20;

A client breaks the BPF shared object into smaller pieces and sends them as the instruction data of Write instructions to the loader where loader writes that data into the program's account data.&#x20;

Once all the pieces are received the client sends a Finalize instruction to the loader, the loader then validates that the BPF data is valid and marks the program account as executable.&#x20;

Once the program account is marked executable, subsequent transactions may issue instructions for that program to process.

When an instruction is directed at an executable BPF program the loader configures the program's execution environment, serializes the program's input parameters, calls the program's entrypoint, and reports any errors encountered.

For further information see deploying&#x20;

### Input Parameter Serialization

BPF loaders serialize the program input parameters into a byte array that is then passed to the program's entrypoint, where the program is responsible for deserializing it on-chain.&#x20;

One of the changes between the deprecated loader and the current loader is that the input parameters are serialized in a way that results in various parameters falling on aligned offsets within the aligned byte array.&#x20;

This allows deserialization implementations to directly reference the byte array and provide aligned pointers to the program.

For language specific information about serialization see:

* Rust program parameter deserialization

The latest loader serializes the program input parameters as follows (all encoding is little endian):

* 8 bytes unsigned number of accounts
* For each account
* * 1 byte indicating if this is a duplicate account, if not a duplicate then the value is 0xff, otherwise the value is the index of the account it is a duplicate of.  &#x20;
  * &#x20;If duplicate: 7 bytes of padding  &#x20;
  * &#x20;If not duplicate:       &#x20;
  *

  ```
  * 1 byte boolean, true if account is a signer       &#x20;
  ```

  ```
  * 1 byte boolean, true if account is writable       &#x20;
  * 1 byte boolean, true if account is executable       &#x20;
  * 4 bytes of padding       &#x20;
  * 32 bytes of the account public key       &#x20;
  * 32 bytes of the account's owner public key      &#x20;
  * 8 bytes unsigned number of lamports owned by the account       &#x20;
  * 8 bytes unsigned number of bytes of account data       &#x20;
  * x bytes of account data       &#x20;
  * 10k bytes of padding, used for realloc       &#x20;
  * enough padding to align the offset to 8 bytes.       &#x20;
  * 8 bytes rent epoch





  * 8 bytes of unsigned number of instruction data
  * x bytes of instruction data
  * 32 bytes of the program id
  ```


# Developing with Rust

PUT supports writing on-chain programs using the Rust programming language.

## Project Layout

PUT Rust programs follow the typical Rust project layout:

```
/inc/
/src/
/Cargo.toml
```

PUT Rust programs may depend directly on each other in order to gain access to instruction helpers when making cross-program invocations.&#x20;

When doing so it's important to not pull in the dependent program's entrypoint symbols because they may conflict with the program's own.&#x20;

To avoid this, programs should define an no-entrypoint feature in Cargo.toml and use to exclude the entrypoint.

* Define the feature
* Exclude the entrypoint

Then when other programs include this program as a dependency, they should do so using the no-entrypoint feature.

* Include without entrypoint

## Project Dependencies

At a minimum, PUT Rust programs must pull in the put-program crate.

PUT BPF programs have some restrictions that may prevent the inclusion of some crates as dependencies or require special handling.

For example:

* Crates that require the architecture be a subset of the ones supported by the official toolchain. There is no workaround for this unless that crate is forked and BPF added to that those architecture checks.
* Crates may depend on rand which is not supported in PUT's deterministic program environment. To include a rand dependent crate refer to Depending on Rand.
* Crates may overflow the stack even if the stack overflowing code isn't included in the program itself. For more information refer to Stack.

## How to Build

First setup the environment:

* Install the latest Rust stable from <https://rustup.rs/>
* Install the latest PUT command-line tools

The normal cargo build is available for building programs against your host machine which can be used for unit testing:

```
$ cargo build
```

To build a specific program, such as SPL Token, for the PUT BPF target which can be deployed to the cluster:

```
$ cd <the program directory>
$ cargo build-bpf
```

## How to Test

PUT programs can be unit tested via the traditional cargo test mechanism by exercising program functions directly.

To help facilitate testing in an environment that more closely matches a live cluster, developers can use the program-test crate.&#x20;

The program-test crate starts up a local instance of the runtime and allows tests to send multiple transactions while keeping state for the duration of the test.

For more information the test in sysvar example shows how an instruction containing sysvar account is sent and processed by the program.

## Program Entrypoint

Programs export a known entrypoint symbol which the PUT runtime looks up and calls when invoking a program.&#x20;

PUT supports multiple versions of the BPF loader and the entrypoints may vary between them. Programs must be written for and deployed to the same loader.

&#x20;For more details see the overview.

Currently there are two supported loaders BPF Loader and BPF loader deprecated

They both have the same raw entrypoint definition, the following is the raw symbol that the runtime looks up and calls:

```
#[no_mangle]
pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64;
```

This entrypoint takes a generic byte array which contains the serialized program parameters (program id, accounts, instruction data, etc...).&#x20;

To deserialize the parameters each loader contains its own wrapper macro that exports the raw entrypoint, deserializes the parameters, calls a user defined instruction processing function, and returns the results.

You can find the entrypoint macros here:

* BPF Loader's entrypoint macro
* BPF Loader deprecated's entrypoint macro

The program defined instruction processing function that the entrypoint macros call must be of this form:

```
pub type ProcessInstruction =
    fn(program_id: &Pubkey, accounts: &[AccountInfo], instruction_data: &[u8]) -> ProgramResult;
```

Refer to helloworld's use of the entrypoint as an example of how things fit together.&#x20;

### Parameter Deserialization

Each loader provides a helper function that deserializes the program's input parameters into Rust types.&#x20;

The entrypoint macros automatically calls the deserialization helper:

* BPF Loader deserialization
* BPF Loader deprecated deserialization

Some programs may want to perform deserialization themselves and they can by providing their own implementation of the raw entrypoint.&#x20;

Take note that the provided deserialization functions retain references back to the serialized byte array for variables that the program is allowed to modify (lamports, account data).&#x20;

The reason for this is that upon return the loader will read those modifications so they may be committed.&#x20;

If a program implements their own deserialization function they need to ensure that any modifications the program wishes to commit be written back into the input byte array.

Details on how the loader serializes the program inputs can be found in the Input Parameter Serialization docs.

### Data Types

The loader's entrypoint macros call the program defined instruction processor function with the following parameters:

```
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8]
```

The program id is the public key of the currently executing program.

The accounts is an ordered slice of the accounts referenced by the instruction and represented as an AccountInfo structures.&#x20;

An account's place in the array signifies its meaning,&#x20;

for example, when transferring lamports an instruction may define the first account as the source and the second as the destination.

The members of the AccountInfo structure are read-only except for lamports and data.&#x20;

Both may be modified by the program in accordance with the runtime enforcement policy.&#x20;

Both of these members are protected by the Rust RefCell construct, so they must be borrowed to read or write to them.&#x20;

The reason for this is they both point back to the original input byte array, but there may be multiple entries in the accounts slice that point to the same account.&#x20;

Using RefCell ensures that the program does not accidentally perform overlapping read/writes to the same underlying data via multiple AccountInfo structures.&#x20;

If a program implements their own deserialization function care should be taken to handle duplicate accounts appropriately.

The instruction data is the general purpose byte array from the instruction's instruction data being processed.

## Heap

Rust programs implement the heap directly by defining a custom global\_allocator

Programs may implement their own global\_allocator based on its specific needs.&#x20;

Refer to the custom heap example for more information.

## Restrictions

On-chain Rust programs support most of Rust's libstd, libcore, and liballoc, as well as many 3rd party crates.

There are some limitations since these programs run in a resource-constrained, single-threaded environment, and must be deterministic:

```
No access to
    rand
    std::fs
    std::net
    std::future
    std::process
    std::sync
    std::task
    std::thread
    std::time
Limited access to:
    std::hash
    std::os
Bincode is extremely computationally expensive in both cycles and call depth and should be avoided
String formatting should be avoided since it is also computationally expensive.
No support for println!, print!, the Put logging helpers should be used instead.
The runtime enforces a limit on the number of instructions a program can execute during the processing of one instruction. See computation budget for more information.
```

## Depending on Rand

Programs are constrained to run deterministically, so random numbers are not available.&#x20;

Sometimes a program may depend on a crate that depends itself on rand even if the program does not use any of the random number functionality.&#x20;

If a program depends on rand, the compilation will fail because there is no get-random support for PUT. The error will typically look like this:

```
error: target is not supported, for more information see: https://docs.rs/getrandom/#unsupported-targets
   --> /Users/jack/.cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.1.14/src/lib.rs:257:9
    |
257 | /         compile_error!("\
258 | |             target is not supported, for more information see: \
259 | |             https://docs.rs/getrandom/#unsupported-targets\
260 | |         ");
    | |___________^
```

To work around this dependency issue, add the following dependency to the program's Cargo.toml:

```
getrandom = { version = "0.1.14", features = ["dummy"] }
```

or if the dependency is on getrandom v0.2 add:

```
getrandom = { version = "0.2.2", features = ["custom"] }
```

## Logging

Rust's println! macro is computationally expensive and not supported. Instead the helper macro msg! is provided.

msg! has two forms:

```
msg!("A string");
```

or

```
msg!(0_64, 1_64, 2_64, 3_64, 4_64);
```

Both forms output the results to the program logs. If a program so wishes they can emulate println! by using format!:

```
msg!("Some variable: {:?}", variable);
```

The debugging section has more information about working with program logs the Rust examples contains a logging example.

## Panicking

Rust's panic!, assert!, and internal panic results are printed to the program logs by default.

```
INFO  put_runtime::message_processor] Finalized account CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ
INFO  put_runtime::message_processor] Call BPF program CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ
INFO  put_runtime::message_processor] Program log: Panicked at: 'assertion failed: `(left == right)`
      left: `1`,
     right: `2`', rust/panic/src/lib.rs:22:5
INFO  put_runtime::message_processor] BPF program consumed 5453 of 200000 units
INFO  put_runtime::message_processor] BPF program CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ failed: BPF program panicked
```

### Custom Panic Handler

Programs can override the default panic handler by providing their own implementation.

First define the custom-panic feature in the program's Cargo.toml

```
[features]
default = ["custom-panic"]
custom-panic = []
```

Then provide a custom implementation of the panic handler:

```
#[cfg(all(feature = "custom-panic", target_os = "put"))]
#[no_mangle]
fn custom_panic(info: &core::panic::PanicInfo<'_>) {
    put_program::msg!("program custom panic enabled");
    put_program::msg!("{}", info);
}
```

In the above snippit, the default implementation is shown, but developers may replace that with something that better suits their needs.

One of the side effects of supporting full panic messages by default is that programs incur the cost of pulling in more of Rust's libstd implementation into program's shared object.&#x20;

Typical programs will already be pulling in a fair amount of libstd and may not notice much of an increase in the shared object size.&#x20;

But programs that explicitly attempt to be very small by avoiding libstd may take a significant impact (\~25kb).&#x20;

To eliminate that impact, programs can provide their own custom panic handler with an empty implementation.

```
#[cfg(all(feature = "custom-panic", target_os = "put"))]
#[no_mangle]
fn custom_panic(info: &core::panic::PanicInfo<'_>) {
    // Do nothing to save space
}
```

## Compute Budget

Use the system call sol\_log\_compute\_units() to log a message containing the remaining number of compute units the program may consume before execution is halted

See compute budget for more information.

## ELF Dump

The BPF shared object internals can be dumped to a text file to gain more insight into a program's composition and what it may be doing at runtime.

The dump will contain both the ELF information as well as a list of all the symbols and the instructions that implement them.&#x20;

Some of the BPF loader's error log messages will reference specific instruction numbers where the error occurred.&#x20;

These references can be looked up in the ELF dump to identify the offending instruction and its context.

To create a dump file:

```
$ cd <program directory>
$ cargo build-bpf --dump
```

## Examples

The PUT Program Library github repo contains a collection of Rust examples.


# Deploying

Deploying Programs&#x20;

<figure><img src="/files/fPqZRGL4iAFuPaJQKrfo" alt=""><figcaption></figcaption></figure>

As shown in the diagram above, a program author creates a program, compiles it to an ELF shared object containing BPF bytecode, and uploads it to the PUT cluster with a special deploy transaction.&#x20;

The cluster makes it available to clients via a program ID.&#x20;

The program ID is an address specified when deploying and is used to reference the program in subsequent transactions.

Upon a successful deployment the account that holds the program is marked executable.&#x20;

If the program is marked "final", its account data become permanently immutable.&#x20;

If any changes are required to the finalized program (features, patches, etc...) the new program must be deployed to a new program ID.

If a program is upgradeable, the account that holds the program is marked executable, but it is possible to redeploy a new shared object to the same program ID, provided that the program's upgrade authority signs the transaction.

The PUT command line interface supports deploying programs, for more information see the deploy command line usage documentation.


# Debugging

Debugging Programs

PUT programs run on-chain, so debugging them in the wild can be challenging. To make debugging programs easier, developers can write unit tests that directly test their program's execution via the PUT runtime, or run a local cluster that will allow RPC clients to interact with their program.

## Running unit tests

```
Testing with Rust
```

## Logging

During program execution both the runtime and the program log status and error messages.

For information about how to log from a program see the language specific documentation:

```
Logging from a Rust program
```

When running a local cluster the logs are written to stdout as long as they are enabled via the RUST\_LOG log mask. From the perspective of program development it is helpful to focus on just the runtime and program logs and not the rest of the cluster logs. To focus in on program specific information the following log mask is recommended:

export RUST\_LOG=put\_runtime::system\_instruction\_processor=trace,put\_runtime::message\_processor=info,put\_bpf\_loader=debug,put\_rbpf=debug

Log messages coming directly from the program (not the runtime) will be displayed in the form:

Program log:&#x20;

## Error Handling

The amount of information that can be communicated via a transaction error is limited but there are many points of possible failures. The following are possible failure points and information about what errors to expect and where to get more information:

```
The BPF loader may fail to parse the program, this should not happen since the loader has already finalized the program's account data.
    InstructionError::InvalidAccountData will be returned as part of the transaction error.
The BPF loader may fail to setup the program's execution environment
    InstructionError::Custom(0x0b9f_0001) will be returned as part of the transaction error. "0x0b9f_0001" is the hexadecimal representation of VirtualMachineCreationFailed.
The BPF loader may have detected a fatal error during program executions (things like panics, memory violations, system call errors, etc...)
    InstructionError::Custom(0x0b9f_0002) will be returned as part of the transaction error. "0x0b9f_0002" is the hexadecimal representation of VirtualMachineFailedToRunProgram.
The program itself may return an error
    InstructionError::Custom(<user defined value>) will be returned. The "user defined value" must not conflict with any of the builtin runtime program errors. Programs typically use enumeration types to define error codes starting at zero so they won't conflict.
```

In the case of VirtualMachineFailedToRunProgram errors, more information about the specifics of what failed are written to the program's execution logs.

For example, an access violation involving the stack will look something like this:

BPF program 4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM failed: out of bounds memory store (insn #615), addr 0x200001e38/8&#x20;

## Monitoring Compute Budget Consumption

The program can log the remaining number of compute units it will be allowed before program execution is halted. Programs can use these logs to wrap operations they wish to profile.

```
Log the remaining compute units from a Rust program
```

See compute budget for more information.&#x20;

## ELF Dump

The BPF shared object internals can be dumped to a text file to gain more insight into a program's composition and what it may be doing at runtime.

```
Create a dump file of a Rust program
```

## Instruction Tracing

During execution the runtime BPF interpreter can be configured to log a trace message for each BPF instruction executed. This can be very helpful for things like pin-pointing the runtime context leading up to a memory access violation.

The trace logs together with the ELF dump can provide a lot of insight (though the traces produce a lot of information).

To turn on BPF interpreter trace messages in a local cluster configure the put\_rbpf level in RUST\_LOG to trace. For example:

export RUST\_LOG=put\_rbpf=trace


# Program Examples

Program Examples&#x20;

## Helloworld

Hello World is a project that demonstrates how to use the PUT Javascript API and both Rust and C programs to build, deploy, and interact with programs on the PUT blockchain.

The project comprises of:

* An on-chain hello world program
* A client that can send a "hello" to an account and get back the number of times "hello" has been sent

### Build and Run\#

fetch the latest version of the example code:&#x20;

```
$ git clone https://github.com/put-labs/example-helloworld.git 
$ cd example-helloworld
```


# FAQ

When writing or interacting with PUT programs, there are common questions or challenges that often come up. Below are resources to help answer these questions.

If not addressed here, ask on StackOverflow with the PUT tag or check out the PUT #developer-support&#x20;

## CallDepth error

This error means that that cross-program invocation exceeded the allowed invocation call depth.

See cross-program invocation Call Depth&#x20;

## CallDepthExceeded error

This error means the BPF stack depth was exceeded.

See call depth&#x20;

## Computational constraints\#

See computational constraints&#x20;

## Float Rust types\#

See float support

## &#x20;Heap size\#

See heap&#x20;

## InvalidAccountData

This program error can happen for a lot of reasons.&#x20;

Usually, it's caused by passing an account to the program that the program is not expecting, either in the wrong position in the instruction or an account not compatible with the instruction being executed.

An implementation of a program might also cause this error when performing a cross-program instruction and forgetting to provide the account for the program that you are calling.&#x20;

## InvalidInstructionData\#

This program error can occur while trying to deserialize the instruction, check that the structure passed in matches exactly the instruction.&#x20;

There may be some padding between fields.&#x20;

If the program implements the Rust Pack trait then try packing and unpacking the instruction type T to determine the exact encoding the program expects:

<https://github.com/put-labs/put/blob/v1.4/sdk/program/src/program\\_pack.rs&#x20>;

## MissingRequiredSignature\#

Some instructions require the account to be a signer; this error is returned if an account is expected to be signed but is not.

An implementation of a program might also cause this error when performing a cross-program invocation that requires a signed program address, but the passed signer seeds passed to invoke\_signed don't match the signer seeds used to create the program address create\_program\_address.&#x20;

## rand Rust dependency causes compilation failure

See Rust Project Dependencies&#x20;

## Rust restrictions

See Rust restrictions&#x20;

## Stack size

See stack


# Native Programs


# Overview

## Native Programs

PUT contains a small handful of native programs, which are required to run validator nodes.&#x20;

Unlike third-party programs, the native programs are part of the validator implementation and can be upgraded as part of cluster upgrades.&#x20;

Upgrades may occur to add features, fix bugs, or improve performance. Interface changes to individual instructions should rarely, if ever, occur.&#x20;

Instead, when change is needed, new instructions are added and previous ones are marked deprecated.&#x20;

Apps can upgrade on their own timeline without concern of breakages across upgrades.

For each native program the program id and description each supported instruction is provided.&#x20;

A transaction can mix and match instructions from different programs, as well include instructions from on-chain programs.

## System Program

Create new accounts, allocate account data, assign accounts to owning programs, transfer lamports from System Program owned accounts and pay transaction fees.

```
Program id: 11111111111111111111111111111111
Instructions: SystemInstruction
```

## Config Program

Add configuration data to the chain and the list of public keys that are permitted to modify it

```
Program id: Config1111111111111111111111111111111111111
Instructions: config_instruction
```

Unlike the other programs, the Config program does not define any individual instructions. It has just one implicit instruction, a "store" instruction. Its instruction data is a set of keys that gate access to the account, and the data to store in it.

## Stake Program

Create and manage accounts representing stake and rewards for delegations to validators.

```
Program id: Stake11111111111111111111111111111111111111
Instructions: StakeInstruction
```

## Vote Program

Create and manage accounts that track validator voting state and rewards.

```
Program id: Vote111111111111111111111111111111111111111
Instructions: VoteInstruction
```

## BPF Loader

Deploys, upgrades, and executes programs on the chain.

```
Program id: BPFLoaderUpgradeab1e11111111111111111111111
Instructions: LoaderInstruction
```

The BPF Upgradeable Loader marks itself as "owner" of the executable and program-data accounts it creates to store your program. When a user invokes an instruction via a program id, the PUT runtime will load both your the program and its owner, the BPF Upgradeable Loader. The runtime then passes your program to the BPF Upgradeable Loader to process the instruction.

More information about deployment

## Ed25519 Program

Verify ed25519 signature program. This program takes an ed25519 signature, public key, and message. Multiple signatures can be verified. If any of the signatures fail to verify, an error is returned.

```
Program id: Ed25519SigVerify111111111111111111111111111
Instructions: new_ed25519_instruction
```

The ed25519 program processes an instruction. The first u8 is a count of the number of signatures to check, which is followed by a single byte padding. After that, the following struct is serialized, one for each signature to check.

```
struct Ed25519SignatureOffsets {
    signature_offset: u16,             // offset to ed25519 signature of 64 bytes
    signature_instruction_index: u16,  // instruction index to find signature
    public_key_offset: u16,            // offset to public key of 32 bytes
    public_key_instruction_index: u16, // instruction index to find public key
    message_data_offset: u16,          // offset to start of message data
    message_data_size: u16,            // size of message data
    message_instruction_index: u16,    // index of instruction data to get message data
}
```

Pseudo code of the operation:

```
process_instruction() {
    for i in 0..count {
        // i'th index values referenced:
        instructions = &transaction.message().instructions
        instruction_index = ed25519_signature_instruction_index != u16::MAX ? ed25519_signature_instruction_index : current_instruction;
        signature = instructions[instruction_index].data[ed25519_signature_offset..ed25519_signature_offset + 64]
        instruction_index = ed25519_pubkey_instruction_index != u16::MAX ? ed25519_pubkey_instruction_index : current_instruction;
        pubkey = instructions[instruction_index].data[ed25519_pubkey_offset..ed25519_pubkey_offset + 32]
        instruction_index = ed25519_message_instruction_index != u16::MAX ? ed25519_message_instruction_index : current_instruction;
        message = instructions[instruction_index].data[ed25519_message_data_offset..ed25519_message_data_offset + ed25519_message_data_size]
        if pubkey.verify(signature, message) != Success {
            return Error
        }
    }
    return Success
}
```

## Secp256k1 Program

Verify secp256k1 public key recovery operations (ecrecover).

```
Program id: KeccakSecp256k11111111111111111111111111111
Instructions: new_secp256k1_instruction
```

The secp256k1 program processes an instruction which takes in as the first byte a count of the following struct serialized in the instruction data:

```
struct Secp256k1SignatureOffsets {
    secp_signature_key_offset: u16,        // offset to [signature,recovery_id,etherum_address] of 64+1+20 bytes
    secp_signature_instruction_index: u8,  // instruction index to find data
    secp_pubkey_offset: u16,               // offset to [signature,recovery_id] of 64+1 bytes
    secp_signature_instruction_index: u8,  // instruction index to find data
    secp_message_data_offset: u16,         // offset to start of message data
    secp_message_data_size: u16,           // size of message data
    secp_message_instruction_index: u8,    // index of instruction data to get message data
}
```

Pseudo code of the operation:

```
process_instruction() {
  for i in 0..count {
      // i'th index values referenced:
      instructions = &transaction.message().instructions
      signature = instructions[secp_signature_instruction_index].data[secp_signature_offset..secp_signature_offset + 64]
      recovery_id = instructions[secp_signature_instruction_index].data[secp_signature_offset + 64]
      ref_eth_pubkey = instructions[secp_pubkey_instruction_index].data[secp_pubkey_offset..secp_pubkey_offset + 32]
      message_hash = keccak256(instructions[secp_message_instruction_index].data[secp_message_data_offset..secp_message_data_offset + secp_message_data_size])
      pubkey = ecrecover(signature, recovery_id, message_hash)
      eth_pubkey = keccak256(pubkey[1..])[12..]
      if eth_pubkey != ref_eth_pubkey {
          return Error
      }
  }
  return Success
}
```

This allows the user to specify any instruction data in the transaction for signature and message data. By specifying a special instructions sysvar, one can also receive data from the transaction itself.

Cost of the transaction will count the number of signatures to verify multiplied by the signature cost verify multiplier.

### Optimization notes

The operation will have to take place after (at least partial) deserialization, but all inputs come from the transaction data itself, this allows it to be relatively easy to execute in parallel to transaction processing and PoH verification.


# Sysvar Cluster Data

## Sysvar Cluster Data

PUT exposes a variety of cluster state data to programs via sysvar accounts.&#x20;

These accounts are populated at known addresses published along with the account layouts in the put-program crate, and outlined below.

There are two ways for a program to access a sysvar.

The first is to query the sysvar at runtime via the sysvar's get() function:

```
let clock = Clock::get()
```

The following sysvars support get:

```
Clock
EpochSchedule
Fees
Rent
```

The second is to pass the sysvar to the program as an account by including its address as one of the accounts in the Instruction and then deserializing the data during execution.&#x20;

Access to sysvars accounts is always readonly.

```
let clock_sysvar_info = next_account_info(account_info_iter)?;
let clock = Clock::from_account_info(&clock_sysvar_info)?;
```

The first method is more efficient and does not require that the sysvar account be passed to the program, or specified in the Instruction the program is processing.

## Clock

The Clock sysvar contains data on cluster time, including the current slot, epoch, and estimated wall-clock Unix timestamp. It is updated every slot.

```
Address: SysvarC1ock11111111111111111111111111111111

Layout: Clock

Fields:
    slot: the current slot
    epoch_start_timestamp: the Unix timestamp of the first slot in this epoch. In the first slot of an epoch, this timestamp is identical to the unix_timestamp (below).
    epoch: the current epoch
    leader_schedule_epoch: the most recent epoch for which the leader schedule has already been generated
    unix_timestamp: the Unix timestamp of this slot.

Each slot has an estimated duration based on Proof of History. But in reality, slots may elapse faster and slower than this estimate. As a result, the Unix timestamp of a slot is generated based on oracle input from voting validators. This timestamp is calculated as the stake-weighted median of timestamp estimates provided by votes, bounded by the expected time elapsed since the start of the epoch.

More explicitly: for each slot, the most recent vote timestamp provided by each validator is used to generate a timestamp estimate for the current slot (the elapsed slots since the vote timestamp are assumed to be Bank::ns_per_slot). Each timestamp estimate is associated with the stake delegated to that vote account to create a distribution of timestamps by stake. The median timestamp is used as the unix_timestamp, unless the elapsed time since the epoch_start_timestamp has deviated from the expected elapsed time by more than 25%.
```

## EpochSchedule

The EpochSchedule sysvar contains epoch scheduling constants that are set in genesis, and enables calculating the number of slots in a given epoch, the epoch for a given slot, etc. (Note: the epoch schedule is distinct from the leader schedule)

```
Address: SysvarEpochSchedu1e111111111111111111111111
Layout: EpochSchedule
```

## Fees

The Fees sysvar contains the fee calculator for the current slot.

&#x20;It is updated every slot, based on the fee-rate governor.

```
Address: SysvarFees111111111111111111111111111111111
Layout: Fees
```

## Instructions

The Instructions sysvar contains the serialized instructions in a Message while that Message is being processed.&#x20;

This allows program instructions to reference other instructions in the same transaction. Read more information on instruction introspection.

```
Address: Sysvar1nstructions1111111111111111111111111
Layout: Instructions
```

## RecentBlockhashes

The RecentBlockhashes sysvar contains the active recent blockhashes as well as their associated fee calculators. It is updated every slot. Entries are ordered by descending block height, so the first entry holds the most recent block hash, and the last entry holds an old block hash.

```
Address: SysvarRecentB1ockHashes11111111111111111111
Layout: RecentBlockhashes
```

## Rent

The Rent sysvar contains the rental rate. Currently, the rate is static and set in genesis. The Rent burn percentage is modified by manual feature activation.

```
Address: SysvarRent111111111111111111111111111111111
Layout: Rent
```

## SlotHashes

The SlotHashes sysvar contains the most recent hashes of the slot's parent banks. It is updated every slot.

```
Address: SysvarS1otHashes111111111111111111111111111
Layout: SlotHashes
```

## SlotHistory

The SlotHistory sysvar contains a bitvector of slots present over the last epoch. It is updated every slot.

```
Address: SysvarS1otHistory11111111111111111111111111
Layout: SlotHistory
```

## StakeHistory

The StakeHistory sysvar contains the history of cluster-wide stake activations and de-activations per epoch. It is updated at the start of every epoch.

```
Address: SysvarStakeHistory1111111111111111111111111
Layout: StakeHistory
```


# Local Development


# PUT Test Validator

## PUT Test Validator

During early stage development, it is often convenient to target a cluster with fewer restrictions and more configuration options than the public offerings provide. This is easily achieved with the put-test-validator binary, which starts a full-featured, single-node cluster on the developer's workstation.

## Advantages

```
No RPC rate-limits
No airdrop limits
Direct on-chain program deployment (--bpf-program ...)
Clone accounts from a public cluster, including programs (--clone ...)
Load accounts from files
Configurable transaction history retention (--limit-ledger-size ...)
Configurable epoch length (--slots-per-epoch ...)
Jump to an arbitrary slot (--warp-slot ...)
```

## Installation

The put-test-validator binary ships with the PUT CLI Tool Suite. Install before continuing.

## Running

First take a look at the configuration options

```
put-test-validator --help
```

Next start the test validator

```
put-test-validator
```

By default, basic status information is printed while the process is running. See Appendix I for details

```
Ledger location: test-ledger
Log: test-ledger/validator.log
Identity: EPhgPANa5Rh2wa4V2jxt7YbtWa3Uyw4sTeZ13cQjDDB8
Genesis Hash: 4754oPEMhAKy14CZc8GzQUP93CB4ouELyaTs4P8ittYn
Version: 1.6.7
Shred Version: 13286
Gossip Address: 127.0.0.1:1024
TPU Address: 127.0.0.1:1027
JSON RPC URL: http://127.0.0.1:8899
⠈ 00:36:02 | Processed Slot: 5142 | Confirmed Slot: 5142 | Finalized Slot: 5110 | Snapshot Slot: 5100 | Transactions: 5142 | ◎499.974295000
```

Leave put-test-validator running in its own terminal. When it is no longer needed, it can be stopped with ctrl-c.

## Interacting

Open a new terminal to interact with a running put-test-validator instance using other binaries from the PUT CLI Tool Suite or your own client software.

Configure the CLI Tool Suite to target a local cluster by default#

```
put config set --url http://127.0.0.1:8899
```

Verify the CLI Tool Suite configuration#

```
put genesis-hash

NOTE: The result should match the Genesis Hash: field in the put-test-validator status output
```

Check the wallet balance#

```
put balance

NOTE: Error: No such file or directory (os error 2) means that the default wallet does not yet exist. Create it with put-keygen new.
NOTE: If the wallet has a zero PUT balance, airdrop some localnet PUT with put airdrop 10
```

Perform a basic transfer transaction#

```
put transfer EPhgPANa5Rh2wa4V2jxt7YbtWa3Uyw4sTeZ13cQjDDB8 1
```

Monitor msg!() output from on-chain programs#

```
put logs

NOTE: This command needs to be running when the target transaction is executed. Run it in its own terminal
```

## Appendix I: Status Output

```
Ledger location: test-ledger
```

File path of the ledger storage directory. This directory can get large. Store less transaction history with --limit-ledger-size ... or relocate it with --ledger ...

```
Log: test-ledger/validator.log
```

File path of the validator text log file. The log can also be streamed by passing --log. Status output is suppressed in this case.

```
Identity: EPhgPANa5Rh2wa4V2jxt7YbtWa3Uyw4sTeZ13cQjDDB8
```

The validator's identity in the gossip network

```
Version: 1.6.7
```

The software version

```
Gossip Address: 127.0.0.1:1024
TPU Address: 127.0.0.1:1027
JSON RPC URL: http://127.0.0.1:8899
```

The network address of the Gossip, Transaction Processing Unit and JSON RPC service, respectively

```
⠈ 00:36:02 | Processed Slot: 5142 | Confirmed Slot: 5142 | Finalized Slot: 5110 | Snapshot Slot: 5100 | Transactions: 5142 | ◎499.974295000
```

Session running time, current slot of the the three block commitment levels, slot height of the last snapshot, transaction count, voting authority balance

## Appendix II: Runtime Features

By default, the test validator runs with all runtime features activated.

You can verify this using the PUT command-line tools:

```
put feature status -ul
```

Since this may not always be desired, especially when testing programs meant for deployment to mainnet, the CLI provides an option to deactivate specific features:

```
put-test-validator --deactivate-feature <FEATURE_PUBKEY_1> --deactivate-feature <FEATURE_PUBKEY_2>
```


# Backward Compatibility Policy

## Backward Compatibility Policy

As the PUT developer ecosystem grows, so does the need for clear expectations around breaking API and behavior changes affecting applications and tooling built for PUT. In a perfect world, PUT development could continue at a very fast pace without ever causing issues for existing developers. However, some compromises will need to be made and so this document attempts to clarify and codify the process for new releases.

## Expectations

* PUT software releases include APIs, SDKs, and CLI tooling (with a few exceptions).
* PUT software releases follow semantic versioning, more details below.
* Software for a `MINOR` version release will be compatible across all software on the same `MAJOR` version.

## Deprecation Process

1. In any `PATCH` or `MINOR` release, a feature, API, endpoint, etc. could be marked as deprecated.
2. According to code upgrade difficulty, some features will be remain deprecated for a few release cycles.
3. In a future `MAJOR` release, deprecated features will be removed in an incompatible way.

## Release Cadence

The PUT RPC API, Rust SDK, CLI tooling, and BPF Program SDK are all updated and shipped along with each PUT software release and should always be compatible between PATCH updates of a particular MINOR version release.

Release Channels#

* `edge` software that contains cutting-edge features with no backward compatibility policy
* `beta` software that runs on the Solana Testnet cluster
* `stable` software that run on the Solana Mainnet Beta and Devnet clusters

Major Releases (x.0.0)#

MAJOR version releases (e.g. 2.0.0) may contain breaking changes and removal of previously deprecated features. Client SDKs and tooling will begin using new features and endpoints that were enabled in the previous MAJOR version.

Minor Releases (1.x.0)#

New features and proposal implementations are added to new MINOR version releases (e.g. 1.4.0) and are first run on PUT's Testnet cluster. While running on the testnet, MINOR versions are considered to be in the beta release channel. After those changes have been patched as needed and proven to be reliable, the MINOR version will be upgraded to the stable release channel and deployed to the Mainnet Beta cluster.

Patch Releases (1.0.x)#

Low risk features, non-breaking changes, and security and bug fixes are shipped as part of PATCH version releases (e.g. 1.0.11). Patches may be applied to both beta and stable release channels.

## RPC API

Patch releases:

* Bug fixes
* Security fixes
* Endpoint / feature deprecation

Minor releases:

* New RPC endpoints and features

Major releases:

* Removal of deprecated features

## Rust Crates

* `put-sdk` - Rust SDK for creating transactions and parsing account state
* `put-program` - Rust SDK for writing programs
* `put-client` - Rust client for connecting to RPC API
* `put-cli-config` - Rust client for managing PUT CLI config files
* `put-geyser-plugin-interface` - Rust interface for developing PUT Geyser plugins.

Patch releases:

* Bug fixes
* Security fixes
* Performance improvements

Minor releases:

* New APIs

Major releases

* Removal of deprecated APIs
* Backwards incompatible behavior changes

## CLI Tools

Patch releases:

* Bug and security fixes
* Performance improvements
* Subcommand / argument deprecation

Minor releases:

* New subcommands

Major releases:

* Switch to new RPC API endpoints / configuration introduced in the previous major version.
* Removal of deprecated features

## Runtime Features

New PUT runtime features are feature-switched and manually activated. Runtime features include: the introduction of new native programs, sysvars, and syscalls; and changes to their behavior. Feature activation is cluster agnostic, allowing confidence to be built on Testnet before activation on Mainnet-beta.

The release process is as follows:

1. New runtime feature is included in a new release, deactivated by default
2. Once sufficient staked validators upgrade to the new release, the runtime feature switch is activated manually with an instruction
3. The feature takes effect at the beginning of the next epoch

## Infrastructure Changes

### Public API Nodes

PUT provides publicly available RPC API nodes for all developers to use. The PUT team will make their best effort to communicate any changes to the host, port, rate-limiting behavior, availability, etc. However, we recommend that developers rely on their own validator nodes to discourage dependence upon PUT operated nodes.

### Local cluster scripts and Docker images

Breaking changes will be limited to MAJOR version updates. MINOR and PATCH updates should always be backwards compatible.

## Exceptions

### Web3 JavaScript SDK

The Web3.JS SDK also follows semantic versioning specifications but is shipped separately from PUT software releases.

### Attack Vectors

If a new attack vector is discovered in existing code, the above processes may be circumvented in order to rapidly deploy a fix, depending on the severity of the issue.


# Validators


# Running a Validator

## Running a Validator

This section describes how to run a PUT validator node.

There are several clusters available to connect to， see [choosing a Cluster](https://docs.put.com/cli/connecting-to-a-cluster) for an overview of each.


# Getting Started


# Validator Requirements

Validator Requirements

## Minimum PUT requirements

There is no strict minimum amount of PUT required to run a validator on PUT.

However in order to participate in consensus, a vote account is required which has a rent-exempt reserve of 0.02685864 PUT.&#x20;

Voting also requires sending a vote transaction for each block the validator agrees with, which can cost up to 1.1 PUT per day.

## Hardware Recommendations

```
CPU
    12 cores / 24 threads, or more
    2.8GHz, or faster
    AVX2 instruction support (to use official release binaries, self-compile otherwise)
    Support for AVX512f and/or SHA-NI instructions is helpful
    The AMD Zen3 series is popular with the validator community
RAM
    256GB, or more
    Motherboard with 256GB capacity suggested
Disk
    PCIe Gen3 x4 NVME SSD, or better
    Accounts: 500GB, or larger. High TBW (Total Bytes Written)
    Ledger: 1TB or larger. High TBW suggested
    OS: (Optional) 500GB, or larger. SATA OK
    The OS may be installed on the ledger disk, though testing has shown better performance with the ledger on its own disk
    Accounts and ledger can be stored on the same disk, however due to high IOPS, this is not recommended
    The Samsung 970 and 980 Pro series SSDs are popular with the validator community
GPUs
    Not strictly necessary at this time
    Motherboard and power supply speced to add one or more high-end GPUs in the future suggested
```

### RPC Node Recommendations

The hardware recommendations above should be considered bare minimums if the validator is intended to be employed as an RPC node.&#x20;

To provide full functionality and improved reliability, the following adjustments should be made.

```
CPU
    16 cores / 32 threads, or more
RAM
    256 GB, or more
Disk
    Consider a larger ledger disk if longer transaction history is required
    Accounts and ledger should not be stored on the same disk
```

## Virtual machines on Cloud Platforms

While you can run a validator on a cloud computing platform, it may not be cost-efficient over the long term.

However, it may be convenient to run non-voting api nodes on VM instances for your own internal usage. This use case includes exchanges and services built on PUT.

In fact, the mainnet-beta validators operated by the team are currently (Mar. 2021) run on GCE n2-standard-32 (32 vCPUs, 128 GB memory) instances with 2048 GB SSD for operational convenience.

For other cloud platforms, select instance types with similar specs.

Also note that egress internet traffic usage may turn out to be high, especially for the case of running staked validators.

## Software

```
We build and run on Ubuntu 20.04.
See Installing PUT for the current PUT software release.
```

Prebuilt binaries are available for Linux x86\_64 on CPUs supporting AVX2 (Ubuntu 20.04 recommended). MacOS or WSL users may build from source.

## Networking

Internet service should be at least 300Mbit/s symmetric, commercial. 1GBit/s preferred

### Port Forwarding

The following ports need to be open to the internet for both inbound and outbound

It is not recommended to run a validator behind a NAT.

&#x20;Operators who choose to do so should be comfortable configuring their networking equipment and debugging any traversal issues on their own.

### Required

```
8000-10000 TCP/UDP - P2P protocols (gossip, turbine, repair, etc). This can be limited to any free 13 port range with --dynamic-port-range
```

### Optional

For security purposes, it is not suggested that the following ports be open to the internet on staked, mainnet-beta validators.

```
8899 TCP - JSONRPC over HTTP. Change with `--rpc-port RPC_PORT``
8900 TCP - JSONRPC over Websockets. Derived. Uses RPC_PORT + 1
```

## GPU Requirements

CUDA is required to make use of the GPU on your system.&#x20;

The provided PUT release binaries are built on Ubuntu 20.04 with CUDA Toolkit 10.1 update 1.

&#x20;If your machine is using a different CUDA version then you will need to rebuild from source.


# Voting Setup


# Starting a Validator

Starting a Validator

## Configure PUT CLI

The PUT CLI includes get and set configuration commands to automatically set the --url argument for cli commands. For example:

Set Testnet:

```
put config set --url https://rpc-test.put.com
```

OR

Set Mainnet:

```
put config set --url https://rpc.put.com
```

While this section demonstrates how to connect to the Devnet cluster, the steps are similar for the other PUT Clusters.

## Confirm The Cluster Is Reachable

Before attaching a validator node, sanity check that the cluster is accessible to your machine by fetching the transaction count:

```
put transaction-count
```

View the metrics dashboard for more detail on cluster activity.

## Enabling CUDA

If your machine has a GPU with CUDA installed (Linux-only currently), include the --cuda argument to put-validator.

When your validator is started look for the following log message to indicate that CUDA is enabled: "\[\<timestamp> put::validator] CUDA is enabled"

## System Tuning

### Linux

### Automatic

The PUT repo includes a daemon to adjust system settings to optimize performance (namely by increasing the OS UDP buffer and file mapping limits).

The daemon (put-sys-tuner) is included in the PUT binary release.&#x20;

Restart it, before restarting your validator, after each software upgrade to ensure that the latest recommended settings are applied.

To run it:

```
sudo $(command -v put-sys-tuner) --user $(whoami) > sys-tuner.log 2>&1 &
```

### Manual

If you would prefer to manage system settings on your own, you may do so with the following commands.

### Optimize sysctl knobs

```
sudo bash -c "cat >/etc/sysctl.d/21-put-validator.conf <<EOF
# Increase UDP buffer sizes
net.core.rmem_default = 134217728
net.core.rmem_max = 134217728
net.core.wmem_default = 134217728
net.core.wmem_max = 134217728

# Increase memory mapped files limit
vm.max_map_count = 1000000

# Increase number of allowed open file descriptors
fs.nr_open = 1000000
EOF"
sudo sysctl -p /etc/sysctl.d/21-put-validator.conf
```

### Increase systemd and session file limits

Add

```
LimitNOFILE=1000000
```

to the \[Service] section of your systemd service file, if you use one, otherwise add

```
DefaultLimitNOFILE=1000000
```

to the \[Manager] section of /etc/systemd/system.conf.

```
sudo systemctl daemon-reload
sudo bash -c "cat >/etc/security/limits.d/90-put-nofiles.conf <<EOF

# Increase process file descriptor count limit
* - nofile 1000000
EOF"
### Close all open sessions (log out then, in again) ###
```

## Generate identity

Create an identity keypair for your validator by running:

```
put-keygen new -o ~/validator-keypair.json
```

The identity public key can now be viewed by running:

```
put-keygen pubkey ~/validator-keypair.json

Note: The "validator-keypair.json” file is also your (ed25519) private key.
```

### Paper Wallet identity

You can create a paper wallet for your identity file instead of writing the keypair file to disk with:

```
put-keygen new --no-outfile
```

The corresponding identity public key can now be viewed by running:

```
put-keygen pubkey ASK
```

and then entering your seed phrase.

See Paper Wallet Usage for more info.

### Vanity Keypair

You can generate a custom vanity keypair using put-keygen. For instance:

```
put-keygen grind --starts-with e1v1s:1
```

You may request that the generated vanity keypair be expressed as a seed phrase which allows recovery of the keypair from the seed phrase and an optionally supplied passphrase (note that this is significantly slower than grinding without a mnemonic):

```
put-keygen grind --use-mnemonic --starts-with e1v1s:1
```

Depending on the string requested, it may take days to find a match...

Your validator identity keypair uniquely identifies your validator within the network. It is crucial to back-up this information.

If you don’t back up this information, you WILL NOT BE ABLE TO RECOVER YOUR VALIDATOR if you lose access to it. If this happens, YOU WILL LOSE YOUR ALLOCATION OF PUT TOO.

To back-up your validator identify keypair, back-up your "validator-keypair.json” file or your seed phrase to a secure location.

## More PUT CLI Configuration

Now that you have a keypair, set the PUT configuration to use your validator keypair for all following commands:

```
put config set --keypair ~/validator-keypair.json
```

You should see the following output:

```
Config File: /home/put/.config/put/cli/config.yml
RPC URL: https://rpc-test.put.com
WebSocket URL: wss://rpc-test.put.com/ (computed)
Keypair Path: /home/put/validator-keypair.json
Commitment: confirmed
```

## Airdrop & Check Validator Balance

Airdrop yourself some PUT to get started:

```
put airdrop 1
```

Note that airdrops are only available on Testnet, limited to 2 PUT per request.

To view your current balance:

```
put balance
```

Or to see in finer detail:

```
put balance --lamports
```

Read more about the difference between PUT and lamports here.

## Create Authorized Withdrawer Account

If you haven't already done so, create an authorized-withdrawer keypair to be used as the ultimate authority over your validator.&#x20;

This keypair will have the authority to withdraw from your vote account, and will have the additional authority to change all other aspects of your vote account.&#x20;

Needless to say, this is a very important keypair as anyone who possesses it can make any changes to your vote account, including taking ownership of it permanently.&#x20;

So it is very important to keep your authorized-withdrawer keypair in a safe location.

&#x20;It does not need to be stored on your validator, and should not be stored anywhere from where it could be accessed by unauthorized parties.&#x20;

To create your authorized-withdrawer keypair:

```
put-keygen new -o ~/authorized-withdrawer-keypair.json
```

## Create Vote Account

If you haven’t already done so, create a vote-account keypair and create the vote account on the network.

&#x20;If you have completed this step, you should see the “vote-account-keypair.json” in your PUT runtime directory:

```
put-keygen new -o ~/vote-account-keypair.json
```

The following command can be used to create your vote account on the blockchain with all the default options:

```
put create-vote-account ~/vote-account-keypair.json ~/validator-keypair.json ~/authorized-withdrawer-keypair.json
```

Remember to move your authorized withdrawer keypair into a very secure location after running the above command.

Read more about creating and managing a vote account.

## Known validators

If you know and respect other validator operators, you can specify this on the command line with the --known-validator argument to put-validator.&#x20;

You can specify multiple ones by repeating the argument --known-validator --known-validator .&#x20;

This has two effects, one is when the validator is booting with --only-known-rpc, it will only ask that set of known nodes for downloading genesis and snapshot data.&#x20;

Another is that in combination with the --halt-on-known-validators-accounts-hash-mismatch option, it will monitor the merkle root hash of the entire accounts state of other known nodes on gossip and if the hashes produce any mismatch, the validator will halt the node to prevent the validator from voting or processing potentially incorrect state values.&#x20;

At the moment, the slot that the validator publishes the hash on is tied to the snapshot interval. For the feature to be effective, all validators in the known set should be set to the same snapshot interval value or multiples of the same.

It is highly recommended you use these options to prevent malicious snapshot state download or account state divergence.

## Connect Your Validator

Connect to the cluster by running:

```
put-validator \
  --identity ~/validator-keypair.json \
  --vote-account ~/vote-account-keypair.json \
  --rpc-port 8899 \
  --entrypoint entrypoint 47.243.176.201:8001 \
  --limit-ledger-size \
  --log ~/put-validator.log
```

To force validator logging to the conpute add a --log - argument, otherwise the validator will automatically log to a file.

The ledger will be placed in the ledger/ directory by default, use the --ledger argument to specify a different location.

Note: You can use a paper wallet seed phrase for your --identity and/or --authorized-voter keypairs.   To use these, pass the respective argument as put-validator --identity ASK ... --authorized-voter ASK ... and you will be prompted to enter your seed phrases and optional passphrase.

Confirm your validator is connected to the network by opening a new terminal and running:

```
put gossip
```

If your validator is connected, its public key and IP address will appear in the list.&#x20;

### Controlling local network port allocation

By default the validator will dynamically select available network ports in the 8000-10000 range, and may be overridden with --dynamic-port-range.&#x20;

For example, put-validator --dynamic-port-range 11000-11020 ... will restrict the validator to ports 11000-11020.

### &#x20;Limiting ledger size to conserve disk space

The --limit-ledger-size parameter allows you to specify how many ledger shreds your node retains on disk.&#x20;

If you do not include this parameter, the validator will keep the entire ledger until it runs out of disk space.

The default value attempts to keep the ledger disk usage under 500GB.&#x20;

More or less disk usage may be requested by adding an argument to --limit-ledger-size if desired.&#x20;

Check put-validator --help for the default limit value used by --limit-ledger-size.

More information about selecting a custom limit value is available [here](https://github.com/put-labs/put/blob/36167b032c03fc7d1d8c288bb621920aaf903311/core/src/ledger_cleanup_service.rs#L23-L34) .

### Systemd Unit

Running the validator as a systemd unit is one easy way to manage running in the background.

Assuming you have a user called PUT on your machine, create the file /etc/systemd/system/put.service with the following:

```
[Unit]
Description=PUT Validator
After=network.target
Wants=put-sys-tuner.service
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=1
User=PUT
LimitNOFILE=1000000
LogRateLimitIntervalSec=0
Environment="PATH=/bin:/usr/bin:/home/put/.local/share/put/install/active_release/bin"
ExecStart=/home/put/bin/validator.sh

[Install]
WantedBy=multi-user.target
```

Now create /home/put/bin/validator.sh to include the desired put-validator command-line. Ensure that the 'exec' command is used to start the validator process (i.e. "exec put-validator ...").&#x20;

This is important because without it, logrotate will end up killing the validator every time the logs are rotated.

Ensure that running /home/put/bin/validator.sh manually starts the validator as expected.

&#x20;Don't forget to mark it executable with chmod +x /home/put/bin/validator.sh

Start the service with:

```
$ sudo systemctl enable --now put
```

### Logging

Log output tuning#

The messages that a validator emits to the log can be controlled by the RUST\_LOG environment variable.

&#x20;Details can by found in the [documentation](https://docs.rs/env_logger/latest/env_logger/#enabling-logging) for the `env_logger` Rust crate.

Note that if logging output is reduced, this may make it difficult to debug issues encountered later.&#x20;

Should support be sought from the team, any changes will need to be reverted and the issue reproduced before help can be provided.

Log rotation#

The validator log file, as specified by --log \~/put-validator.log, can get very large over time and it's recommended that log rotation be configured.

The validator will re-open its log file when it receives the USR1 signal, which is the basic primitive that enables log rotation.

If the validator is being started by a wrapper shell script, it is important to launch the process with exec (exec put-validator ...) when using logrotate.&#x20;

This will prevent the USR1 signal from being sent to the script's process instead of the validator's, which will kill them both.

Using logrotate#

An example setup for the logrotate, which assumes that the validator is running as a systemd service called put.service and writes a log file at /home/put/put-validator.log:

```
# Setup log rotation

cat > logrotate.put <<EOF
/home/put/put-validator.log {
  rotate 7
  daily
  missingok
  postrotate
    systemctl kill -s USR1 put.service
  endscript
}
EOF
sudo cp logrotate.put /etc/logrotate.d/put
systemctl restart logrotate.service
```

As mentioned earlier, be sure that if you use logrotate, any script you create which starts the PUT validator process uses "exec" to do so (example: "exec put-validator ..."); otherwise, when logrotate sends its signal to the validator, the enclosing script will die and take the validator process with it.

### Disable port checks to speed up restarts

Once your validator is operating normally, you can reduce the time it takes to restart your validator by adding the --no-port-check flag to your put-validator command-line.&#x20;

### Using a ramdisk with spill-over into swap for the accounts database to reduce SSD wear

If your machine has plenty of RAM, a tmpfs ramdisk ([tmpfs](https://man7.org/linux/man-pages/man5/tmpfs.5.html)) may be used to hold the accounts database

When using tmpfs it's essential to also configure swap on your machine as well to avoid running out of tmpfs space periodically.

A 300GB tmpfs partition is recommended, with an accompanying 250GB swap partition.

Example configuration:

1. sudo mkdir /mnt/put-accounts
2. Add a 300GB tmpfs parition by adding a new line containing tmpfs /mnt/put-accounts tmpfs rw,size=300G,user=put 0 0 to /etc/fstab (assuming your validator is running under the user "put"). CAREFUL: If you incorrectly edit /etc/fstab your machine may no longer boot
3. Create at least 250GB of swap space  Choose a device to use in place of SWAPDEV for the remainder of these instructions. Ideally select a free disk partition of 250GB or greater on a fast disk. If one is not available, create a swap file with sudo dd if=/dev/zero of=/swapfile bs=1MiB count=250KiB, set its permissions with sudo chmod 0600 /swapfile and use /swapfile as SWAPDEV for the remainder of these instructions Format the device for usage as swap with sudo mkswap SWAPDEV
4. Add the swap file to /etc/fstab with a new line containing SWAPDEV swap swap defaults 0 0
5. Enable swap with sudo swapon -a and mount the tmpfs with sudo mount /mnt/put-accounts/
6. Confirm swap is active with free -g and the tmpfs is mounted with mount

Now add the --accounts /mnt/put-accounts argument to your PUT-validator command-line arguments and restart the validator.

### Account indexing

As the number of populated accounts on the cluster grows, account-data RPC requests that scan the entire account set -- like getProgramAccounts and PPL-token-specific requests -- may perform poorly.&#x20;

If your validator needs to support any of these requests, you can use the --account-index parameter to activate one or more in-memory account indexes that significantly improve RPC performance by indexing accounts by the key field.&#x20;

Currently supports the following parameter values:

* program-id: each account indexed by its owning program; used by getProgramAccounts
* ppl-token-mint: each PPL token account indexed by its token Mint; used by getTokenAccountsByDelegate, and getTokenLargestAccounts
* ppl-token-owner: each PPL token account indexed by the token-owner address; used by getTokenAccountsByOwner, and getProgramAccounts requests that include an spl-token-owner filter.


# Vote Account Management

## Vote Account Management

This page describes how to set up an on-chain vote account.&#x20;

Creating a vote account is needed if you plan to run a validator node on Solana.

## Create a Vote Account

A vote account can be created with the create-vote-account command.&#x20;

The vote account can be configured when first created or after the validator is running.&#x20;

All aspects of the vote account can be changed except for the vote account address, which is fixed for the lifetime of the account.

### Configure an Existing Vote Account

* To change the validator identity, use vote-update-validator.
* To change the vote authority, use vote-authorize-voter-checked.
* To change the authorized withdrawer, use vote-authorize-withdrawer-checked.
* To change the commission, use vote-update-commission.

## Vote Account Structure

### Vote Account Address

A vote account is created at an address that is either the public key of a keypair file, or at a derived address based on a keypair file's public key and a seed string.

The address of a vote account is never needed to sign any transactions, but is just used to look up the account information.

When someone wants to delegate tokens in a stake account, the delegation command is pointed at the vote account address of the validator to whom the token-holder wants to delegate.

### Validator Identity

The validator identity is a system account that is used to pay for all the vote transaction fees submitted to the vote account.&#x20;

Because the validator is expected to vote on most valid blocks it receives, the validator identity account is frequently (potentially multiple times per second) signing transactions and paying fees.&#x20;

For this reason the validator identity keypair must be stored as a "hot wallet" in a keypair file on the same system the validator process is running.

Because a hot wallet is generally less secure than an offline or "cold" wallet, the validator operator may choose to store only enough PUT on the identity account to cover voting fees for a limited amount of time, such as a few weeks or months.&#x20;

The validator identity account could be periodically topped off from a more secure wallet.

This practice can reduce the risk of loss of funds if the validator node's disk or file system becomes compromised or corrupted.

The validator identity is required to be provided when a vote account is created.&#x20;

The validator identity can also be changed after an account is created by using the vote-update-validator command.

### Vote Authority

The vote authority keypair is used to sign each vote transaction the validator node wants to submit to the cluster.&#x20;

This doesn't necessarily have to be unique from the validator identity, as you will see later in this document.&#x20;

Because the vote authority, like the validator identity, is signing transactions frequently, this also must be a hot keypair on the same file system as the validator process.

The vote authority can be set to the same address as the validator identity.&#x20;

If the validator identity is also the vote authority, only one signature per vote transaction is needed in order to both sign the vote and pay the transaction fee.&#x20;

Because transaction fees on Solana are assessed per-signature, having one signer instead of two will result in half the transaction fee paid compared to setting the vote authority and validator identity to two different accounts.

The vote authority can be set when the vote account is created. If it is not provided, the default behavior is to assign it the same as the validator identity.&#x20;

The vote authority can be changed later with the vote-authorize-voter-checked command.

The vote authority can be changed at most once per epoch. If the authority is changed with vote-authorize-voter-checked, this will not take effect until the beginning of the next epoch.&#x20;

To support a smooth transition of the vote signing, put-validator allows the --authorized-voter argument to be specified multiple times.&#x20;

This allows the validator process to keep voting successfully when the network reaches an epoch boundary at which the validator's vote authority account changes.

### Authorized Withdrawer

The authorized withdrawer keypair is used to withdraw funds from a vote account using the withdraw-from-vote-account command.

&#x20;Any network rewards a validator earns are deposited into the vote account and are only retrievable by signing with the authorized withdrawer keypair.

The authorized withdrawer is also required to sign any transaction to change a vote account's commission, and to change the validator identity on a vote account.

Because theft of a authorized withdrawer keypair can give complete control over the operation of a validator to an attacker, is is advised to keep the withdraw authority keypair in an offline/cold wallet in a secure location.&#x20;

The withdraw authority keypair is not needed during operation of a validator and should not stored on the validator itself.

The authorized withdrawer must be set when the vote account is created.&#x20;

It must not be set to a keypair that is the same as either the validator identity keypair or the vote authority keypair.

The authorized withdrawer can be changed later with the vote-authorize-withdrawer-checked command.

### Commission

Commission is the percent of network rewards earned by a validator that are deposited into the validator's vote account.&#x20;

The remainder of the rewards are distributed to all of the stake accounts delegated to that vote account, proportional to the active stake weight of each stake account.

For example, if a vote account has a commission of 10%, for all rewards earned by that validator in a given epoch, 10% of these rewards will be deposited into the vote account in the first block of the following epoch.&#x20;

The remaining 90% will be deposited into delegated stake accounts as immediately active stake.

A validator may choose to set a low commission to try to attract more stake delegations as a lower commission results in a larger percentage of rewards passed along to the delegator.&#x20;

As there are costs associated with setting up and operating a validator node, a validator would ideally set a high enough commission to at least cover their expenses.

Commission can be set upon vote account creation with the --commission option.&#x20;

If it is not provided, it will default to 100%, which will result in all rewards deposited in the vote account, and none passed on to any delegated stake accounts.

Commission can also be changed later with the vote-update-commission command.

When setting the commission, only integer values in the set \[0-100] are accepted.&#x20;

The integer represents the number of percentage points for the commission, so creating an account with --commission 10 will set a 10% commission.

## Key Rotation

Rotating the vote account authority keys require special handling when dealing with a live validator.

Note that vote account key rotation has no effect on the stake accounts that have been delegate to the vote account.&#x20;

For example it is possible to use key rotation to transfer all authority of a vote account from one entity to another without any impact to staking rewards.

### Vote Account Validator Identity

You will need access to the authorized withdrawer keypair for the vote account to change the validator identity. The follow steps assume that \~/authorized\_withdrawer.json is that keypair.

1. Create the new validator identity keypair, put-keygen new -o \~/new-validator-keypair.json.
2. Ensure that the new identity account has been funded, PUT transfer \~/new-validator-keypair.json 500.
3. Run PUT vote-update-validator \~/vote-account-keypair.json \~/new-validator-keypair.json \~/authorized\_withdrawer.json to modify the validator identity in your vote account
4. Restart your validator with the new identity keypair for the --identity argument

Additional steps are required if your validator has stake. The leader schedule is computed two epochs in advance.&#x20;

Therefore if your old validator identity was in the leader schedule, it will remain in the leader schedule for up to two epochs after the validator identity change.&#x20;

If extra steps are not taken your validator will produce no blocks until your new validator identity is added to the leader schedule.

After your validator is restarted with the new identity keypair, per step 4, start a second non-voting validator on a different machine with the old identity keypair without providing the --vote-account argument, as well as with the --no-wait-for-vote-to-start-leader argument.

This temporary validator should be run for two full epochs. During this time it will:

* Produce blocks for the remaining slots that are assigned to your old validator identity
* Receive the transaction fees and rent rewards for your old validator identity

It is safe to stop this temporary validator when your old validator identity is no longer listed in the PUT leader-schedule output.

### Vote Account Authorized Voter

The vote authority keypair may only be changed at epoch boundaries and requires some additional arguments to put-validator for a seamless migration.

1. Run put epoch-info. If there is not much time remaining time in the current epoch, consider waiting for the next epoch to allow your validator plenty of time to restart and catch up.
2. Create the new vote authority keypair, put-keygen new -o \~/new-vote-authority.json.
3. Determine the current vote authority keypair by running put vote-account \~/vote-account-keypair.json. It may be validator's identity account (the default) or some other keypair. The following steps assume that \~/validator-keypair.json is that keypair.
4. Run put vote-authorize-voter-checked \~/vote-account-keypair.json \~/validator-keypair.json \~/new-vote-authority.json. The new vote authority is scheduled to become active starting at the next epoch.
5. put-validator now needs to be restarted with the old and new vote authority keypairs, so that it can smoothly transition at the next epoch. Add the two arguments on restart: --authorized-voter \~/validator-keypair.json --authorized-voter \~/new-vote-authority.json
6. After the cluster reaches the next epoch, remove the --authorized-voter \~/validator-keypair.json argument and restart put-validator, as the old vote authority keypair is no longer required.

### Vote Account Authorized Withdrawer

No special handling or timing considerations are required.&#x20;

Use the PUT vote-authorize-withdrawer-checked command as needed.&#x20;

### Consider Durable Nonces for a Trustless Transfer of the Authorized Voter or Withdrawer

If the Authorized Voter or Withdrawer is to be transferred to another entity then a two-stage signing process using a Durable Nonce is recommended.

1. Entity B creates a durable nonce using PUT create-nonce-account
2. Entity B then runs a put vote-authorize-voter-checked or put vote-authorize-withdrawer-checked command, including: the --sign-only argumentthe --nonce, --nonce-authority, and --blockhash arguments to specify the nonce particulars the address of the Entity A's existing authority, and the keypair for Entity B's new authority
3. When the put vote-authorize-...-checked command successfully executes, it will output transaction signatures that Entity B must share with Entity A
4. Entity A then runs a similar put vote-authorize-voter-checked or put vote-authorize-withdrawer-checked command with the following changes:

* the --sign-only argument is removed, and replaced with a --signer argument for each of the signatures provided by Entity B
* the address of Entity A's existing authority is replaced with the corresponding keypair, and the the keypair for Entity B's new authority is replaced with the correponding address

On success the authority is now changed without Entity A or B having to reveal keypairs to the other even though both entities signed the transaction.

## Close a Vote Account

A vote account can be closed with the close-vote-account command. Closing a vote account withdraws all remaining PUT funds to a supplied recipient address and renders it invalid as a vote account. It is not possible to close a vote account with active stake.


# Staking

By default your validator will have no stake.&#x20;

This means it will be ineligible to become leader.

## Monitoring Catch Up

To delegate stake, first make sure your validator is running and has caught up to the cluster. It may take some time to catch up after your validator boots.&#x20;

Use the catchup command to monitor your validator through this process: put catchup \~/validator-keypair.json

Until your validator has caught up, it will not be able to vote successfully and stake cannot be delegated to it.

Also if you find the cluster's slot advancing faster than yours, you will likely never catch up.&#x20;

This typically implies some kind of networking issue between your validator and the rest of the cluster.

## Create Stake Keypair

If you haven’t already done so, create a staking keypair.&#x20;

If you have completed this step, you should see the “validator-stake-keypair.json” in your Solana runtime directory.

```
put-keygen new -o ~/validator-stake-keypair.json
```

## Delegate Stake

Now delegate 1 PUT to your validator by first creating your stake account:

```
put create-stake-account ~/validator-stake-keypair.json 1
```

and then delegating that stake to your validator:

```
put delegate-stake ~/validator-stake-keypair.json ~/vote-account-keypair.json

Don’t delegate your remaining PUT, as your validator will use those tokens to vote.
```

Stakes can be re-delegated to another node at any time with the same command, but only one re-delegation is permitted per epoch:

```
put delegate-stake ~/validator-stake-keypair.json ~/some-other-vote-account-keypair.json
```

Assuming the node is voting, now you're up and running and generating validator rewards. Rewards are paid automatically on epoch boundaries.

The rewards lamports earned are split between your stake account and the vote account according to the commission rate set in the vote account.&#x20;

Rewards can only be earned while the validator is up and running. Further, once staked, the validator becomes an important part of the network.&#x20;

In order to safely remove a validator from the network, first deactivate its stake.

At the end of each slot, a validator is expected to send a vote transaction.&#x20;

These vote transactions are paid for by lamports from a validator's identity account.

This is a normal transaction so the standard transaction fee will apply. The transaction fee range is defined by the genesis block.&#x20;

The actual fee will fluctuate based on transaction load.&#x20;

You can determine the current fee via the RPC API “getRecentBlockhash” before submitting a transaction.

Learn more about transaction fees here.

## Validator Stake Warm-up

To combat various attacks on consensus, new stake delegations are subject to a warm-up period.

Monitor a validator's stake during warmup by:

* View your vote account:put vote-account \~/vote-account-keypair.json This displays the current state of all the votes the validator has submitted to the network.
* View your stake account, the delegation preference and details of your stake:put stake-account \~/validator-stake-keypair.json
* put validators displays the current active stake of all validators, including yours
* put stake-history shows the history of stake warming up and cooling down over recent epochs
* Look for log messages on your validator indicating your next leader slot: \[2019-09-27T20:16:00.319721164Z INFO put\_core::replay\_stage] \<VALIDATOR\_IDENTITY\_PUBKEY> voted and reset PoH at tick height ####. My next leader slot is ####
* Once your stake is warmed up, you will see a stake balance listed for your validator by running put validators

## Monitor Your Staked Validator

Confirm your validator becomes a leader

* After your validator is caught up, use the put balance command to monitor the earnings as your validator is selected as leader and collects transaction fees
* PUT nodes offer a number of useful JSON-RPC methods to return information about the network and your validator's participation. Make a request by using curl (or another http client of your choosing), specifying the desired method in JSON-RPC-formatted data. For example:

```
// Request curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}' http://localhost:8899

// Result {"jsonrpc":"2.0","result":{"epoch":3,"slotIndex":126,"slotsInEpoch":256},"id":1}
```

Helpful JSON-RPC methods:

* getEpochInfoAn epoch is the time, i.e. number of slots, for which a leader schedule is valid. This will tell you what the current epoch is and how far into it the cluster is.
* getVoteAccounts This will tell you how much active stake your validator currently has. A % of the validator's stake is activated on an epoch boundary. You can learn more about staking on PUT here.
* getLeaderSchedule At any given moment, the network expects only one validator to produce ledger entries. The validator currently selected to produce ledger entries is called the “leader”. This will return the complete leader schedule (on a slot-by-slot basis) for currently activated stake, the identity pubkey will show up 1 or more times here.

## Deactivating Stake

Before detaching your validator from the cluster, you should deactivate the stake that was previously delegated by running:

```
put deactivate-stake ~/validator-stake-keypair.json
```

Stake is not deactivated immediately and instead cools down in a similar fashion as stake warm up.&#x20;

Your validator should remain attached to the cluster while the stake is cooling down. While cooling down, your stake will continue to earn rewards.&#x20;

Only after stake cooldown is it safe to turn off your validator or withdraw it from the network. Cooldown may take several epochs to complete, depending on active stake and the size of your stake.

Note that a stake account may only be used once, so after deactivation, use the cli's withdraw-stake command to recover the previously staked lamports.


# Monitoring a Validator

Monitoring a Validator

## Check Gossip

Confirm the IP address and identity pubkey of your validator is visible in the gossip network by running:

```
put gossip
```

## Check Your Balance

Your account balance should decrease by the transaction fee amount as your validator submits votes, and increase after serving as the leader. Pass the --lamports are to observe in finer detail:

```
put balance --lamports
```

## Check Vote Activity

The put vote-account command displays the recent voting activity from your validator:

```
put vote-account ~/vote-account-keypair.json
```

## Get Cluster Info

There are several useful JSON-RPC endpoints for monitoring your validator on the cluster, as well as the health of the cluster:

```
# Similar to put-gossip, you should see your validator in the list of cluster nodes
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getClusterNodes"}' https://rpc.putdev.com:8889

# If your validator is properly voting, it should appear in the list of `current` vote accounts. If staked, `stake` should be > 0
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getVoteAccounts"}' https://rpc.putdev.com:8889

# Returns the current leader schedule
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"}' https://rpc.putdev.com:8889

# Returns info about the current epoch. slotIndex should progress on subsequent calls.
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getEpochInfo"}' https://rpc.putdev.com:8889
```


# Publishing Validator Info

You can publish your validator information to the chain to be publicly visible to other users.

## Run PUT validator-info

Run the PUT CLI to populate a validator info account:

```
put validator-info publish --keypair ~/validator-keypair.json <VALIDATOR_INFO_ARGS> <VALIDATOR_NAME>
```

For details about optional fields for VALIDATOR\_INFO\_ARGS: PUT validator-info publish --help

## Example Commands

Example publish command:

```
put validator-info publish "Elvis Validator" -n elvis -w "https://elvis-validates.com"
```

Example query command:

```
put validator-info get
```

which outputs

```
Validator info from 8WdJvDz6obhADdxpGCiJKZsDYwTLNEDFizayqziDc9ah
  Validator pubkey: 6dMH3u76qZ7XG4bVboVRnBHR2FfrxEqTTTyj4xmyDMWo
  Info: {"keybaseUsername":"elvis","name":"Elvis Validator","website":"https://elvis-validates.com"}
```

## Keybase

Including a Keybase username allows client applications (like the Solana Network Explorer) to automatically pull in your validator public profile, including cryptographic proofs, brand identity, etc. To connect your validator pubkey with Keybase:

1. Join <https://keybase.io/> and complete the profile for your validator
2. Add your validator **identity pubkey** to Keybase:
   * Create an empty file on your local computer called `validator-<PUBKEY>`
   * In Keybase, navigate to the Files section, and upload your pubkey file to

     a PUT subdirectory in your public folder: `/keybase/public/<KEYBASE_USERNAME>/put`
   * To check your pubkey, ensure you can successfully browse to

     `https://keybase.pub/<KEYBASE_USERNAME>/put/validator-<PUBKEY>`
3. Add or update your PUT`validator-info` with your Keybase username. The

   CLI will verify the `validator-<PUBKEY>` file


# Failover Setup

A simple two machine instance failover method is described here, which allows you to:

* upgrade your validator software with virtually no down time, and
* failover to the secondary instance when your monitoring detects a problem with the primary instance without any safety issues that would otherwise be associated with running two instances of your validator.

You will need two validator-class machines for your primary and secondary validator. A third machine for running an etcd cluster, which is used to store the tower voting record for your validator.

## Setup

### etcd cluster setup

There is ample documentation regarding etcd setup and configuration at <https://etcd.io/>, please generally familiarize yourself with etcd before continuing.

It's recommended that etcd be installed on a separate machine from your primary and secondary validator machines. This machine must be highly available, and depending on your needs you may wish to configure etcd with more than just one node.

First install etcd as desired for your machine. Then TLS certificates must be created for authentication between the etcd cluster and your validator. Here is one way to do this:

With Golang installed, run go install github.com/cloudflare/cfssl/cmd/cfssl\@latest. The cfssl program should now be available at \~/go/bin/cfssl. Ensure ~~/go/bin is in your PATH by running PATH=$PATH:~~/go/bin/.

Now create a certificate directory and configuration file:

```
mkdir -p certs/
echo '{"CN":"etcd","hosts":["localhost", "127.0.0.1"],"key":{"algo":"rsa","size":2048}}' > certs/config.json
```

then create certificates for the etcd server and the validator:

```
cfssl gencert -initca certs/config.json | cfssljson -bare certs/etcd-ca
cfssl gencert -ca certs/etcd-ca.pem -ca-key certs/etcd-ca-key.pem certs/config.json | cfssljson -bare certs/validator
cfssl gencert -ca certs/etcd-ca.pem -ca-key certs/etcd-ca-key.pem certs/config.json | cfssljson -bare certs/etcd
```

Copy these files to your primary and secondary validator machines:

* `certs/validator-key.pem`
* `certs/validator.pem`
* `certs/etcd-ca.pem`

and these files to the machine running the etcd server:

* `certs/etcd.pem`
* `certs/etcd-key.pem`
* `certs/etcd-ca.pem`

With this configuration, both the validator and etdc will share the same TLS certificate authority and will each authenticate the other with it.

Start etcd with the following arguments:

```
etcd --auto-compaction-retention 2 --auto-compaction-mode revision \
  --cert-file=certs/etcd.pem --key-file=certs/etcd-key.pem \
  --client-cert-auth \
  --trusted-ca-file=certs/etcd-ca.pem \
  --listen-client-urls=https://127.0.0.1:2379 \
  --advertise-client-urls=https://127.0.0.1:2379
```

and use curl to confirm the etcd TLS certificates are properly configured:

```
curl --cacert certs/etcd-ca.pem https://127.0.0.1:2379/ --cert certs/validator.pem --key certs/validator-key.pem
```

On success, curl will return a 404 response.

For more information on etcd TLS setup, please refer to <https://etcd.io/docs/v3.5/op-guide/security/#example-2-client-to-server-authentication-with-https-client-certificates>

### Primary Validator

The following additional put-validator parameters are required to enable tower storage into etcd:

```
put-validator ... \
  --tower-storage etcd \
  --etcd-cacert-file certs/etcd-ca.pem \
  --etcd-cert-file certs/validator.pem \
  --etcd-key-file certs/validator-key.pem \
  --etcd-endpoint 127.0.0.1:2379  # <-- replace 127.0.0.1 with the actual IP address
```

Note that once running your validator will terminate if it's not able to write its tower into etcd before submitting a vote transaction, so it's essential that your etcd endpoint remain accessible at all times.

### Secondary Validator

Configure the secondary validator like the primary with the exception of the following put-validator command-line argument changes:

* Generate and use a secondary validator identity: `--identity secondary-validator-keypair.json`
* Add `--no-check-vote-account`
* Add `--authorized-voter validator-keypair.json` (where `validator-keypair.json` is the identity keypair for your primary validator)

## Triggering a failover manually

When both validators are running normally and caught up to the cluster, a failover from primary to secondary can be triggered by running the following command on the secondary validator:

```
$ put-validator wait-for-restart-window --identity validator-keypair.json \
  && put-validator set-identity validator-keypair.json
```

The secondary validator will acquire a lock on the tower in etcd to ensure voting and block production safely switches over from the primary validator.

The primary validator will then terminate as soon as it detects the secondary validator using its identity.

Note: When the primary validator restarts (which may be immediate if you have configured your primary validator to do so) it will reclaim its identity from the secondary validator. This will in turn cause the secondary validator to exit. However if/when the secondary validator restarts, it will do so using the secondary validator identity and thus the restart cycle is broken.

## Triggering a failover via monitoring

Monitoring of your choosing can invoke the put-validator set-identity validator-keypair.json command mentioned in the previous section.

It is not necessary to guarantee the primary validator has halted before failing over to the secondary, as the failover process will prevent the primary validator from voting and producing blocks even if it is in an unknown state.

## Validator Software Upgrades

To perform a software upgrade using this failover method:

1. Install the new software version on your primary validator system but do not restart it yet.
2. Trigger a manual failover to your secondary validator. This should cause your primary validator to terminate.
3. When your primary validator restarts it will now be using the new software version.
4. Once the primary validator catches up upgrade the secondary validator at your convenience.


# Troubleshooting

There is a #validator-support Discord channel available to reach other testnet participants, <https://discord.gg/pquxPsq>.

## Useful Links & Discussion

* Network Explorer
* Testnet Metrics Dashboard
* Validator chat channels
  * \#validator-support General support channel for any Validator related queries.
  * \#testnet-announcements The single source of truth for critical information relating Testnet
* Core software repo

Can't find what you're looking for? Send an email to <ryan@put.com> or reach out to @rshea#2622 on Discord.

## Blockstore

The validator blockstore rocksdb database can be inspected using the ldb tool. ldb is part of the rocksdb code base and is also available in the rocksdb-tools package.

RocksDB Administration and Data Access Tool

## Upgrade

If a new software version introduces a new column family to the blockstore, that new (empty) column will be automatically created. This is the same logic that allows a validator to start fresh without the blockstore directory.

## Downgrade

If a new column family has been introduced to the validator blockstore, a subsequent downgrade of the validator to a version that predates the new column family will cause the validator to fail while opening the blockstore during startup.

List column families:&#x20;

&#x20;   ldb --db=/rocksdb/ list\_column\_families

Warning: Please seek guidance on discord before modifying the validator blockstore.

Drop a column family:&#x20;

&#x20;   ldb --db=/rocksdb drop\_column\_family


# Geyser


# Geyser Plugins

## Overview

Validators under heavy RPC loads, such as when serving getProgramAccounts calls, can fall behind the network.&#x20;

To solve this problem, the validator has been enhanced to support a plugin mechanism, called a "Geyser" plugin, through which the information about accounts, slots, blocks, and transactions can be transmitted to external data stores such as relational databases, NoSQL databases or Kafka.&#x20;

RPC services then can be developed to consume data from these external data stores with the possibility of more flexible and targeted optimizations such as caching and indexing.&#x20;

This allows the validator to focus on processing transactions without being slowed down by busy RPC requests.

This document describes the interfaces of the plugin and the referential plugin implementation for the PostgreSQL database.

### Important Crates:

* put-geyser-plugin-interface — This crate defines the plugin interfaces.
* put-accountsdb-plugin-postgres — The crate for the referential plugin implementation for the PostgreSQL database.

## The Plugin Interface

The Plugin interface is declared in put-geyser-plugin-interface. It is defined by the trait GeyserPlugin.&#x20;

The plugin should implement the trait and expose a "C" function \_create\_plugin to return the pointer to this trait. For example, in the referential implementation, the following code instantiates the PostgreSQL plugin GeyserPluginPostgres and returns its pointer.

```
#[no_mangle]
#[allow(improper_ctypes_definitions)]
/// # Safety
///
/// This function returns the GeyserPluginPostgres pointer as trait GeyserPlugin.
pub unsafe extern "C" fn _create_plugin() -> *mut dyn GeyserPlugin {
    let plugin = GeyserPluginPostgres::new();
    let plugin: Box<dyn GeyserPlugin> = Box::new(plugin);
    Box::into_raw(plugin)
}
```

A plugin implementation can implement the on\_load method to initialize itself.&#x20;

This function is invoked after a plugin is dynamically loaded into the validator when it starts.&#x20;

The configuration of the plugin is controlled by a configuration file in JSON5 format. The JSON5 file must have a field libpath that points to the full path name of the shared library implementing the plugin, and may have other configuration information, like connection parameters for the external database.&#x20;

The plugin configuration file is specified by the validator's CLI parameter --geyser-plugin-config and the file must be readable to the validator process.

Please see the config file for the referential PostgreSQL plugin below for an example.

The plugin can implement the on\_unload method to do any cleanup before the plugin is unloaded when the validator is gracefully shutdown.

The plugin framework supports streaming either accounts, transactions or both.&#x20;

A plugin uses the following function to indicate if it is interested in receiving account data:

```
fn account_data_notifications_enabled(&self) -> bool
```

And it uses the following function to indicate if it is interested in receiving transaction data:

```
fn transaction_notifications_enabled(&self) -> bool
```

The following method is used for notifying on an account update:

```
fn update_account(
    &mut self,
    account: ReplicaAccountInfoVersions,
    slot: u64,
    is_startup: bool,
) -> Result<()>
```

The ReplicaAccountInfoVersions struct contains the metadata and data of the account streamed.&#x20;

The slot points to the slot the account is being updated at. When is\_startup is true, it indicates the account is loaded from snapshots when the validator starts up.&#x20;

When is\_startup is false, the account is updated when processing a transaction.

The following method is called when all accounts have been notified when the validator restores the AccountsDb from snapshots at startup.

```
fn notify_end_of_startup(&mut self) -> Result<()>
```

When update\_account is called during processing transactions, the plugin should process the notification as fast as possible because any delay may cause the validator to fall behind the network.&#x20;

Persistence to external data store is best to be done asynchronously.

The following method is used for notifying slot status changes:

```
fn update_slot_status(
    &mut self,
    slot: u64,
    parent: Option<u64>,
    status: SlotStatus,
) -> Result<()>
```

To ensure data consistency, the plugin implementation can choose to abort the validator in case of error persisting to external stores.

&#x20;When the validator restarts the account data will be re-transmitted.

The following method is used for notifying transactions:

```
fn notify_transaction(
    &mut self,
    transaction: ReplicaTransactionInfoVersions,
    slot: u64,
) -> Result<()>
```

The ReplicaTransactionInfoVersionsoVersions struct contains the information about a streamed transaction. It wraps ReplicaTransactionInfo

```
pub struct ReplicaTransactionInfo<'a> {
    /// The first signature of the transaction, used for identifying the transaction.
    pub signature: &'a Signature,

    /// Indicates if the transaction is a simple vote transaction.
    pub is_vote: bool,

    /// The sanitized transaction.
    pub transaction: &'a SanitizedTransaction,

    /// Metadata of the transaction status.
    pub transaction_status_meta: &'a TransactionStatusMeta,
}
```

For details of SanitizedTransaction and TransactionStatusMeta , please refer to put-sdk and put-transaction-status

The slot points to the slot the transaction is executed at.&#x20;

For more details, please refer to the Rust documentation in put-geyser-plugin-interface.

## Example PostgreSQL Plugin

The put-accountsdb-plugin-postgres repository implements a plugin storing account data to a PostgreSQL database to illustrate how a plugin can be developed.

#### Configuration File Format

The plugin is configured using the input configuration file.&#x20;

An example configuration file looks like the following:

```
{
    "libpath": "/put/target/release/libput_geyser_plugin_postgres.so",
    "host": "postgres-server",
    "user": "put",
    "port": 5433,
    "threads": 20,
    "batch_size": 20,
    "panic_on_db_errors": true,
    "accounts_selector" : {
        "accounts" : ["*"]
    }
}
```

The host, user, and port control the PostgreSQL configuration information.&#x20;

For more advanced connection options, please use the connection\_str field.&#x20;

Please see \[Rust postgres configuration] (<https://docs.rs/postgres/0.19.2/postgres/config/struct.Config.html>).

To improve the throughput to the database, the plugin supports connection pooling using multiple threads, each maintaining a connection to the PostgreSQL database.&#x20;

The count of the threads is controlled by the threads field. A higher thread count usually offers better performance.

To further improve performance when saving large numbers of accounts at startup, the plugin uses bulk inserts. The batch size is controlled by the batch\_size parameter.&#x20;

This can help reduce the round trips to the database.

The panic\_on\_db\_errors can be used to panic the validator in case of database errors to ensure data consistency.

### Account Selection

The accounts\_selector can be used to filter the accounts that should be persisted.

For example, one can use the following to persist only the accounts with particular Base58-encoded Pubkeys,

```
"accounts_selector" : {
     "accounts" : ["pubkey-1", "pubkey-2", ..., "pubkey-n"],
}
```

Or use the following to select accounts with certain program owners:

```
"accounts_selector" : {
     "owners" : ["pubkey-owner-1", "pubkey-owner-2", ..., "pubkey-owner-m"],
}
```

To select all accounts, use the wildcard character (\*):

```
"accounts_selector" : {
     "accounts" : ["*"],
}
```

### Transaction Selection

transaction\_selector, controls if and what transactions to store. If this field is missing, none of the transactions are stored.

For example, one can use the following to select only the transactions referencing accounts with particular Base58-encoded Pubkeys,

```
"transaction_selector" : {
    "mentions" : \["pubkey-1", "pubkey-2", ..., "pubkey-n"\],
}
```

The mentions field supports wildcards to select all transaction or all 'vote' transactions. For example, to select all transactions:

```
"transaction_selector" : {
    "mentions" : \["*"\],
}
```

To select all vote transactions:

```
"transaction_selector" : {
    "mentions" : \["all_votes"\],
}
```

### Database Setup

Install PostgreSQL Server#

Please follow PostgreSQL Ubuntu Installation on instructions to install the PostgreSQL database server. For example, to install postgresql-14,

```
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get -y install postgresql-14
```

Control the Database Access#

Modify the pg\_hba.conf as necessary to grant the plugin to access the database.

&#x20;For example, in /etc/postgresql/14/main/pg\_hba.conf, the following entry allows nodes with IPs in the CIDR 10.138.0.0/24 to access all databases.&#x20;

The validator runs in a node with an ip in the specified range.

```
host    all             all             10.138.0.0/24           trust
```

It is recommended to run the database server on a separate node from the validator for better performance.

Configure the Database Performance Parameters#

Please refer to the PostgreSQL Server Configuration for configuration details.&#x20;

The referential implementation uses the following configurations for better database performance in the /etc/postgresql/14/main/postgresql.conf which are different from the default postgresql-14 installation.

```
max_connections = 200                  # (change requires restart)
shared_buffers = 1GB                   # min 128kB
effective_io_concurrency = 1000        # 1-1000; 0 disables prefetching
wal_level = minimal                    # minimal, replica, or logical
fsync = off                            # flush data to disk for crash safety
synchronous_commit = off               # synchronization level;
full_page_writes = off                 # recover from partial page writes
max_wal_senders = 0                    # max number of walsender processes
The sample postgresql.conf can be used for reference.
```

Create the Database Instance and the Role#

Start the server:

```
sudo systemctl start postgresql@14-main
```

Create the database. For example, the following creates a database named 'put':

```
sudo -u postgres createdb put -p 5433
```

Create the database user. For example, the following creates a regular user named 'put':

```
sudo -u postgres createuser -p 5433 put
```

Verify the database is working using psql. For example, assuming the node running PostgreSQL has the ip 10.138.0.9, the following command will land in a shell where SQL commands can be entered:

```
psql -U put -p 5433 -h 10.138.0.9 -w -d put
```

Create the Schema Objects#

Use the create\_schema.sql to create the objects for storing accounts and slots.

Download the script from github:

```
wget https://raw.githubusercontent.com/put-labs/put/a70eb098f4ae9cd359c1e40bbb7752b3dd61de8d/accountsdb-plugin-postgres/scripts/create_schema.sql
```

Then run the script:

```
psql -U put -p 5433 -h 10.138.0.9 -w -d put -f create_schema.sql
```

After this, start the validator with the plugin by using the --geyser-plugin-config argument mentioned above.

Destroy the Schema Objects# To destroy the database objects, created by create\_schema.sql, use drop\_schema.sql. For example,

```
psql -U put -p 5433 -h 10.138.0.9 -w -d put -f drop_schema.sql
```

### Capture Historical Account Data

To capture account historical data, in the configuration file, turn store\_account\_historical\_data to true.

And ensure the database trigger is created to save data in the audit\_table when records in account are updated, as shown in create\_schema.sql,

```
CREATE FUNCTION audit_account_update() RETURNS trigger AS $audit_account_update$
    BEGIN
        INSERT INTO account_audit (pubkey, owner, lamports, slot, executable, rent_epoch, data, write_version, updated_on)
            VALUES (OLD.pubkey, OLD.owner, OLD.lamports, OLD.slot,
                    OLD.executable, OLD.rent_epoch, OLD.data, OLD.write_version, OLD.updated_on);
        RETURN NEW;
    END;

$audit_account_update$ LANGUAGE plpgsql;

CREATE TRIGGER account_update_trigger AFTER UPDATE OR DELETE ON account
    FOR EACH ROW EXECUTE PROCEDURE audit_account_update();
```

The trigger can be dropped to disable this feature, for example,

```
DROP TRIGGER account_update_trigger ON account;
```

Over time, the account\_audit can accumulate large amount of data. You may choose to limit that by deleting older historical data.

For example, the following SQL statement can be used to keep up to 1000 of the most recent records for an account:

```
delete from account_audit a2 where (pubkey, write_version) in
    (select pubkey, write_version from
        (select a.pubkey, a.updated_on, a.slot, a.write_version, a.lamports,
            rank() OVER ( partition by pubkey order by write_version desc) as rnk
            from account_audit a) ranked
            where ranked.rnk > 1000)
        
        
```

### Main Tables

The following are the tables in the Postgres database

| Table          | Description             |
| -------------- | ----------------------- |
| account        | Account data            |
| slot           | Slot metadata           |
| transactio     | Transaction data        |
| account\_audit | Account historical data |

### Performance Considerations

When a validator lacks sufficient compute power, the overhead of saving the account data can cause it to fall behind the network especially when all accounts or a large number of accounts are selected.&#x20;

The node hosting the PostgreSQL database need to be powerful enough to handle the database loads as well.&#x20;

It has been found using GCP n2-standard-64 machine type for the validator and n2-highmem-32 for the PostgreSQL node is adequate for handling transmiting all accounts while keeping up with the network. In addition, it is best to keep the validator and the PostgreSQL in the same local network to reduce latency.&#x20;

You may need to size the validator and database nodes differently if serving other loads.


# Staking


# Staking on PUT

## Staking on PUT

Note before reading: All references to increases in values are in absolute terms with regards to balance of PUT.&#x20;

This document makes no suggestion as to the monetary value of PUT at any time.

By staking your PUT tokens, you help secure the network and earn rewards while doing so.

You can stake by delegating your tokens to validators who process transactions and run the network.

Delegating stake is a shared-risk shared-reward financial model that may provide returns to holders of tokens delegated for a long period.&#x20;

This is achieved by aligning the financial incentives of the token-holders (delegators) and the validators to whom they delegate.

The more stake delegated to a validator, the more often this validator is chosen to write new transactions to the ledger.&#x20;

The more transactions the validator writes, the more rewards the validator and its delegators earn.&#x20;

Validators who configure their systems to be able to process more transactions earn proportionally more rewards and because they keep the network running as fast and as smoothly as possible.

Validators incur costs by running and maintaining their systems, and this is passed on to delegators in the form of a fee collected as a percentage of rewards earned.&#x20;

This fee is known as a commission. Since validators earn more rewards the more stake is delegated to them, they may compete with one another to offer the lowest commission for their services.

You risk losing tokens when staking through a process known as slashing.&#x20;

Slashing involves the removal and destruction of a portion of a validator's delegated stake in response to intentional malicious behavior, such as creating invalid transactions or censoring certain types of transactions or network participants.

When a validator is slashed, all token holders who have delegated stake to that validator lose a portion of their delegation.&#x20;

While this means an immediate loss for the token holder, it also is a loss of future rewards for the validator due to their reduced total delegation.&#x20;

More details on the slashing roadmap can be found here.

Rewards and slashing align validator and token holder interests which helps keep the network secure, robust and performant.

## How do I stake my PUT tokens?

You can stake PUT by moving your tokens into a wallet that supports staking. The wallet provides steps to create a stake account and do the delegation.

### Supported Wallets

Many web and mobile wallets support PUT staking operations.&#x20;

Please check with your favorite wallet's maintainers regarding status

### PUT command line tools

* PUT command line tools can perform all stake operations in conjunction with a CLI-generated keypair file wallet, a paper wallet, or with a connected Ledger Nano. Staking commands using the PUT Command Line Tools.

### Create a Stake Account

Follow the wallet's instructions for creating a staking account. This account will be of a different type than one used to simply send and receive tokens.

### Delegate your Stake

Follow the wallet's instructions for delegating your to your chosen validator.

## Stake Account Details

For more information about the operations and permissions associated with a stake account, please see Stake Accounts


# Stake Account Structure

## Stake Account Structure

A stake account on PUT can be used to delegate tokens to validators on the network to potentially earn rewards for the owner of the stake account.&#x20;

Stake accounts are created and managed differently than a traditional wallet address, known as a system account.&#x20;

A system account is only able to send and receive PUT from other accounts on the network, whereas a stake account supports more complex operations needed to manage a delegation of tokens.

Stake accounts on PUT also work differently than those of other Proof-of-Stake blockchain networks that you may be familiar with.&#x20;

This document describes the high-level structure and functions of a PUT stake account.

## Account Address

Each stake account has a unique address which can be used to look up the account information in the command line or in any network explorer tools.&#x20;

However, unlike a wallet address in which the holder of the address's keypair controls the wallet, the keypair associated with a stake account address does not necessarily have any control over the account.&#x20;

In fact, a keypair or private key may not even exist for a stake account's address.

The only time a stake account's address has a keypair file is when creating a stake account using the command line tools.&#x20;

A new keypair file is created first only to ensure that the stake account's address is new and unique.

## Understanding Account Authorities

Certain types of accounts may have one or more signing authorities associated with a given account.&#x20;

An account authority is used to sign certain transactions for the account it controls.&#x20;

This is different from some other blockchain networks where the holder of the keypair associated with the account's address controls all of the account's activity.

Each stake account has two signing authorities specified by their respective address, each of which is authorized to perform certain operations on the stake account.

The stake authority is used to sign transactions for the following operations:

* Delegating stake
* Deactivating the stake delegation
* Splitting the stake account, creating a new stake account with a portion of the funds in the first account
* Merging two stake accounts into one
* Setting a new stake authority

The withdraw authority signs transactions for the following:

* Withdrawing un-delegated stake into a wallet address
* Setting a new withdraw authority
* Setting a new stake authority

The stake authority and withdraw authority are set when the stake account is created, and they can be changed to authorize a new signing address at any time.&#x20;

The stake and withdraw authority can be the same address or two different addresses.

The withdraw authority keypair holds more control over the account as it is needed to liquidate the tokens in the stake account, and can be used to reset the stake authority if the stake authority keypair becomes lost or compromised.

Securing the withdraw authority against loss or theft is of utmost importance when managing a stake account.

## Multiple Delegations

Each stake account may only be used to delegate to one validator at a time.&#x20;

All of the tokens in the account are either delegated or un-delegated, or in the process of becoming delegated or un-delegated.&#x20;

To delegate a fraction of your tokens to a validator, or to delegate to multiple validators, you must create multiple stake accounts.

This can be accomplished by creating multiple stake accounts from a wallet address containing some tokens, or by creating a single large stake account and using the stake authority to split the account into multiple accounts with token balances of your choosing.

The same stake and withdraw authorities can be assigned to multiple stake accounts.

## Merging stake accounts

Two stake accounts that have the same authorities and lockup can be merged into a single resulting stake account.&#x20;

A merge is possible between two stakes in the following states with no additional conditions:

* two deactivated stakes
* an inactive stake into an activating stake during its activation epoch

For the following cases, the voter pubkey and vote credits observed must match:

* two activated stakes
* two activating accounts that share an activation epoch, during the activation epoch

All other combinations of stake states will fail to merge, including all "transient" states, where a stake is activating or deactivating with a non-zero effective stake.

## Delegation Warmup and Cooldown

When a stake account is delegated, or a delegation is deactivated, the operation does not take effect immediately.

A delegation or deactivation takes several epochs to complete, with a fraction of the delegation becoming active or inactive at each epoch boundary after the transaction containing the instructions has been submitted to the cluster.

There is also a limit on how much total stake can become delegated or deactivated in a single epoch, to prevent large sudden changes in stake across the network as a whole.

&#x20;Since warmup and cooldown are dependent on the behavior of other network participants, their exact duration is difficult to predict.&#x20;

Details on the warmup and cooldown timing can be found here.

## Lockups

Stake accounts can have a lockup which prevents the tokens they hold from being withdrawn before a particular date or epoch has been reached.&#x20;

While locked up, the stake account can still be delegated, un-delegated, or split, and its stake and withdraw authorities can be changed as normal.&#x20;

Only withdrawal into a wallet address is not allowed.

A lockup can only be added when a stake account is first created, but it can be modified later, by the lockup authority or custodian, the address of which is also set when the account is created.

## Destroying a Stake Account

Like other types of accounts on the PUT network, a stake account that has a balance of 0 PUT is no longer tracked.

&#x20;If a stake account is not delegated and all of the tokens it contains are withdrawn to a wallet address, the account at that address is effectively destroyed, and will need to be manually re-created for the address to be used again.

## Viewing Stake Accounts

Stake account details can be viewed on the PUT Explorer by copying and pasting an account address into the search bar.


# Integrations


# Add PUT to Your Exchange

## Add PUT to Your Exchange

This guide describes how to add PUT's native token PUT to your cryptocurrency exchange.

## Node Setup

We highly recommend setting up at least two nodes on high-grade computers/cloud instances, upgrading to newer versions promptly, and keeping an eye on service operations with a bundled monitoring tool.

This setup enables you:

* to have a self-administered gateway to the PUT mainnet-beta cluster to get data and submit withdrawal transactions
* to have full control over how much historical block data is retained
* to maintain your service availability even if one node fails

PUT nodes demand relatively high computing power to handle our fast blocks and high TPS. For specific requirements, please see hardware recommendations.

To run an api node:

* Install the PUT command-line tool suite
* Start the validator with at least the following parameters:

  ```
    put-validator \
      --ledger <LEDGER_PATH> \
      --identity <VALIDATOR_IDENTITY_KEYPAIR> \
      --entrypoint <CLUSTER_ENTRYPOINT> \
      --expected-genesis-hash <EXPECTED_GENESIS_HASH> \
      --rpc-port 8899 \
      --no-voting \
      --enable-rpc-transaction-history \
      --limit-ledger-size \
      --known-validator <VALIDATOR_ADDRESS> \
      --only-known-rpc
  ```

Customize --ledger to your desired ledger storage location, and --rpc-port to the port you want to expose.

The --entrypoint and --expected-genesis-hash parameters are all specific to the cluster you are joining. Current parameters for Mainnet Beta

The --limit-ledger-size parameter allows you to specify how many ledger shreds your node retains on disk.&#x20;

If you do not include this parameter, the validator will keep the entire ledger until it runs out of disk space.&#x20;

The default value attempts to keep the ledger disk usage under 500GB.&#x20;

More or less disk usage may be requested by adding an argument to --limit-ledger-size if desired.&#x20;

Check put-validator --help for the default limit value used by --limit-ledger-size.&#x20;

More information about selecting a custom limit value is available here.

Specifying one or more --known-validator parameters can protect you from booting from a malicious snapshot. More on the value of booting with known validators

Optional parameters to consider:

* \--private-rpc prevents your RPC port from being published for use by other nodes
* \--rpc-bind-address allows you to specify a different IP address to bind the RPC port

### Automatic Restarts and Monitoring

We recommend configuring each of your nodes to restart automatically on exit, to ensure you miss as little data as possible.&#x20;

Running the PUT software as a systemd service is one great option.

For monitoring, we provide put-watchtower, which can monitor your validator and detect with the put-validator process is unhealthy.&#x20;

It can directly be configured to alert you via Slack, Telegram, Discord, or Twillio.&#x20;

For details, run put-watchtower --help.

```
put-watchtower --validator-identity <YOUR VALIDATOR IDENTITY>
```

#### New Software Release Announcements

We release new software frequently (around 1 release / week).&#x20;

Sometimes newer versions include incompatible protocol changes, which necessitate timely software update to avoid errors in processing blocks.

Our official release announcements for all kinds of releases (normal and security) are communicated via a discord channel called #mb-announcement (mb stands for mainnet-beta).

Like staked validators, we expect any exchange-operated validators to be updated at your earliest convenience within a business day or two after a normal release announcement.&#x20;

For security-related releases, more urgent action may be needed.

### Ledger Continuity

By default, each of your nodes will boot from a snapshot provided by one of your known validators.&#x20;

This snapshot reflects the current state of the chain, but does not contain the complete historical ledger.

&#x20;If one of your node exits and boots from a new snapshot, there may be a gap in the ledger on that node.&#x20;

In order to prevent this issue, add the --no-snapshot-fetch parameter to your put-validator command to receive historical ledger data instead of a snapshot.

Do not pass the --no-snapshot-fetch parameter on your initial boot as it's not possible to boot the node all the way from the genesis block.&#x20;

Instead boot from a snapshot first and then add the --no-snapshot-fetch parameter for reboots.

It is important to note that the amount of historical ledger available to your nodes from the rest of the network is limited at any point in time.&#x20;

Once operational if your validators experience significant downtime they may not be able to catch up to the network and will need to download a new snapshot from a known validator.&#x20;

In doing so your validators will now have a gap in its historical ledger data that cannot be filled.

### Minimizing Validator Port Exposure\#

The validator requires that various UDP and TCP ports be open for inbound traffic from all other PUT validators.&#x20;

While this is the most efficient mode of operation, and is strongly recommended, it is possible to restrict the validator to only require inbound traffic from one other PUT validator.

First add the --restricted-repair-only-mode argument.&#x20;

This will cause the validator to operate in a restricted mode where it will not receive pushes from the rest of the validators, and instead will need to continually poll other validators for blocks.&#x20;

The validator will only transmit UDP packets to other validators using the Gossip and ServeR ("serve repair") ports, and only receive UDP packets on its Gossip and Repair ports.

The Gossip port is bi-directional and allows your validator to remain in contact with the rest of the cluster.&#x20;

Your validator transmits on the ServeR to make repair requests to obtaining new blocks from the rest of the network, since Turbine is now disabled.&#x20;

Your validator will then receive repair responses on the Repair port from other validators.

To further restrict the validator to only requesting blocks from one or more validators, first determine the identity pubkey for that validator and add the --gossip-pull-validator PUBKEY --repair-validator PUBKEY arguments for each PUBKEY.&#x20;

This will cause your validator to be a resource drain on each validator that you add, so please do this sparingly and only after consulting with the target validator.

Your validator should now only be communicating with the explicitly listed validators and only on the Gossip, Repair and ServeR ports.

## Setting up Deposit Accounts\#

PUT accounts do not require any on-chain initialization; once they contain some PUT, they exist.&#x20;

To set up a deposit account for your exchange, simply generate a PUT keypair using any of our wallet tools.

We recommend using a unique deposit account for each of your users.

PUT accounts must be made rent-exempt by containing 2-years worth of rent in PUT.&#x20;

In order to find the minimum rent-exempt balance for your deposit accounts, query the getMinimumBalanceForRentExemption endpoint:

```
curl localhost:8899 -X POST -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "getMinimumBalanceForRentExemption",
  "params":[0]
}'

# Result
{"jsonrpc":"2.0","result":890880,"id":1}
```

### Offline Accounts\#

You may wish to keep the keys for one or more collection accounts offline for greater security.&#x20;

If so, you will need to move PUT to hot accounts using our offline methods.

## Listening for Deposits

When a user wants to deposit PUT into your exchange, instruct them to send a transfer to the appropriate deposit address.

### Versioned Transaction Migration

When the Mainnet Beta network starts processing versioned transactions, exchanges MUST make changes.&#x20;

If no changes are made, deposit detection will no longer work properly because fetching a versioned transaction or a block containing versioned transactions will return an error.

* {"maxSupportedTransactionVersion": 0}

&#x20;   The maxSupportedTransactionVersion parameter must be added to getBlock and getTransaction requests to avoid disruption to deposit detection.&#x20;

&#x20;     The latest transaction version is 0 and should be specified as the max supported transaction version value.

It's important to understand that versioned transactions allow users to create transactions that use another set of account keys loaded from on-chain address lookup tables.

* {"encoding": "jsonParsed"}

&#x20;   When fetching blocks and transactions, it's now recommended to use the "jsonParsed" encoding because it includes all transaction account keys (including those from lookup tables) in the message "accountKeys" list.&#x20;

&#x20;   This makes it straightforward to resolve balance changes detailed in preBalances / postBalances and preTokenBalances / postTokenBalances.

&#x20;     If the "json" encoding is used instead, entries in preBalances / postBalances and preTokenBalances / postTokenBalances may refer to account keys that are NOT in the "accountKeys" list and need to be resolved using "loadedAddresses" entries in the transaction metadata.

### Poll for Blocks

To track all the deposit accounts for your exchange, poll for each confirmed block and inspect for addresses of interest, using the JSON-RPC service of your PUT API node.

* To identify which blocks are available, send a getBlocks request, passing the last block you have already processed as the start-slot parameter:

  ```
    curl https://rpc.putdev.com:8889 -X POST -H "Content-Type: application/json" -d '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getBlocks",
      "params": [160017005, 160017015]
    }'
    
    # Result
    {"jsonrpc":"2.0","result":[160017005,160017006,160017007,160017012,160017013,160017014,160017015],"id":1}
    
  ```

Not every slot produces a block, so there may be gaps in the sequence of integers.

* For each block, request its contents with a getBlock request:

### Block Fetching Tips

* {"rewards": false}

By default, fetched blocks will return information about validator fees on each block and staking rewards on epoch boundaries. If you don't need this information, disable it with the "rewards" parameter.

* {"transactionDetails": "accounts"}

By default, fetched blocks will return a lot of transaction info and metadata that isn't necessary for tracking account balances.&#x20;

Set the "transactionDetails" parameter to speed up block fetching.

```
curl https://rpc.putdev.com:8889 -X POST -H 'Content-Type: application/json' -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "getBlock",
  "params": [
    166974442,
    {
      "encoding": "jsonParsed",
      "maxSupportedTransactionVersion": 0,
      "transactionDetails": "accounts",
      "rewards": false
    }
  ]
}'

# Result
{
  "jsonrpc": "2.0",
  "result": {
    "blockHeight": 157201607,
    "blockTime": 1665070281,
    "blockhash": "HKhao674uvFc4wMK1Cm3UyuuGbKExdgPFjXQ5xtvsG3o",
    "parentSlot": 166974441,
    "previousBlockhash": "98CNLU4rsYa2HDUyp7PubU4DhwYJJhSX9v6pvE7SWsAo",
    "transactions": [
      ... (omit)
      {
        "meta": {
          "err": null,
          "fee": 5000,
          "postBalances": [
            1110663066,
            1,
            1040000000
          ],
          "postTokenBalances": [],
          "preBalances": [
            1120668066,
            1,
            1030000000
          ],
          "preTokenBalances": [],
          "status": {
            "Ok": null
          }
        },
        "transaction": {
          "accountKeys": [
            {
              "pubkey": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde",
              "signer": true,
              "source": "transaction",
              "writable": true
            },
            {
              "pubkey": "11111111111111111111111111111111",
              "signer": false,
              "source": "transaction",
              "writable": false
            },
            {
              "pubkey": "G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o",
              "signer": false,
              "source": "lookupTable",
              "writable": true
            }
          ],
          "signatures": [
            "2CxNRsyRT7y88GBwvAB3hRg8wijMSZh3VNYXAdUesGSyvbRJbRR2q9G1KSEpQENmXHmmMLHiXumw4dp8CvzQMjrM"
          ]
        },
        "version": 0
      },
      ... (omit)
    ]
  },
  "id": 1
}
```

The preBalances and postBalances fields allow you to track the balance changes in every account without having to parse the entire transaction.&#x20;

They list the starting and ending balances of each account in lamports, indexed to the accountKeys list. For example, if the deposit address of interest is G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o, this transaction represents a transfer of 1040000000 - 1030000000 = 10,000,000 lamports = 0.01 PUT

If you need more information about the transaction type or other specifics, you can request the block from RPC in binary format, and parse it using either our Rust SDK or Javascript SDK.

### Address History

You can also query the transaction history of a specific address.&#x20;

This is generally not a viable method for tracking all your deposit addresses over all slots, but may be useful for examining a few accounts for a specific period of time.

* Send a getSignaturesForAddress request to the api node:

  ```
    curl localhost:8899 -X POST -H "Content-Type: application/json" -d '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getSignaturesForAddress",
      "params": [
        "3M2b3tLji7rvscqrLAHMukYxDK2nB96Q9hwfV6QkdzBN",
        {
          "limit": 3
        }
      ]
    }'
    
    # Result
    {
      "jsonrpc": "2.0",
      "result": [
        {
          "blockTime": 1662064640,
          "confirmationStatus": "finalized",
          "err": null,
          "memo": null,
          "signature": "3EDRvnD5TbbMS2mCusop6oyHLD8CgnjncaYQd5RXpgnjYUXRCYwiNPmXb6ZG5KdTK4zAaygEhfdLoP7TDzwKBVQp",
          "slot": 148697216
        },
        {
          "blockTime": 1662064434,
          "confirmationStatus": "finalized",
          "err": null,
          "memo": null,
          "signature": "4rPQ5wthgSP1kLdLqcRgQnkYkPAZqjv5vm59LijrQDSKuL2HLmZHoHjdSLDXXWFwWdaKXUuryRBGwEvSxn3TQckY",
          "slot": 148696843
        },
        {
          "blockTime": 1662064341,
          "confirmationStatus": "finalized",
          "err": null,
          "memo": null,
          "signature": "36Q383JMiqiobuPV9qBqy41xjMsVnQBm9rdZSdpbrLTGhSQDTGZJnocM4TQTVfUGfV2vEX9ZB3sex6wUBUWzjEvs",
          "slot": 148696677
        }
      ],
      "id": 1
    }
  ```
* For each signature returned, get the transaction details by sending a getTransaction request:

  ```
    curl https://rpc.putdev.com:8889 -X POST -H 'Content-Type: application/json' -d '{
      "jsonrpc":"2.0",
      "id":1,
      "method":"getTransaction",
      "params":[
        "2CxNRsyRT7y88GBwvAB3hRg8wijMSZh3VNYXAdUesGSyvbRJbRR2q9G1KSEpQENmXHmmMLHiXumw4dp8CvzQMjrM",
        {
          "encoding":"jsonParsed",
          "maxSupportedTransactionVersion":0
        }
      ]
    }'
    
    # Result
    {
      "jsonrpc": "2.0",
      "result": {
        "blockTime": 1665070281,
        "meta": {
          "err": null,
          "fee": 5000,
          "innerInstructions": [],
          "logMessages": [
            "Program 11111111111111111111111111111111 invoke [1]",
            "Program 11111111111111111111111111111111 success"
          ],
          "postBalances": [
            1110663066,
            1,
            1040000000
          ],
          "postTokenBalances": [],
          "preBalances": [
            1120668066,
            1,
            1030000000
          ],
          "preTokenBalances": [],
          "rewards": [],
          "status": {
            "Ok": null
          }
        },
        "slot": 166974442,
        "transaction": {
          "message": {
            "accountKeys": [
              {
                "pubkey": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde",
                "signer": true,
                "source": "transaction",
                "writable": true
              },
              {
                "pubkey": "11111111111111111111111111111111",
                "signer": false,
                "source": "transaction",
                "writable": false
              },
              {
                "pubkey": "G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o",
                "signer": false,
                "source": "lookupTable",
                "writable": true
              }
            ],
            "addressTableLookups": [
              {
                "accountKey": "4syr5pBaboZy4cZyF6sys82uGD7jEvoAP2ZMaoich4fZ",
                "readonlyIndexes": [],
                "writableIndexes": [
                  3
                ]
              }
            ],
            "instructions": [
              {
                "parsed": {
                  "info": {
                    "destination": "G1wZ113tiUHdSpQEBcid8n1x8BAvcWZoZgxPKxgE5B7o",
                    "lamports": 10000000,
                    "source": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde"
                  },
                  "type": "transfer"
                },
                "program": "system",
                "programId": "11111111111111111111111111111111"
              }
            ],
            "recentBlockhash": "BhhivDNgoy4L5tLtHb1s3TP19uUXqKiy4FfUR34d93eT"
          },
          "signatures": [
            "2CxNRsyRT7y88GBwvAB3hRg8wijMSZh3VNYXAdUesGSyvbRJbRR2q9G1KSEpQENmXHmmMLHiXumw4dp8CvzQMjrM"
          ]
        },
        "version": 0
      },
      "id": 1
    }
  ```

## Sending Withdrawals

To accommodate a user's request to withdraw PUT, you must generate a PUT transfer transaction, and send it to the api node to be forwarded to your cluster.

### Synchronous

Sending a synchronous transfer to the PUT cluster allows you to easily ensure that a transfer is successful and finalized by the cluster.

PUT's command-line tool offers a simple command, PUT transfer, to generate, submit, and confirm transfer transactions.&#x20;

By default, this method will wait and track progress on stderr until the transaction has been finalized by the cluster. If the transaction fails, it will report any transaction errors.

```
put transfer <USER_ADDRESS> <AMOUNT> --allow-unfunded-recipient --keypair <KEYPAIR> --url http://localhost:8899
```

The PUT Javascript SDK offers a similar approach for the JS ecosystem.&#x20;

Use the SystemProgram to build a transfer transaction, and submit it using the sendAndConfirmTransaction method.

### Asynchronous

For greater flexibility, you can submit withdrawal transfers asynchronously. In these cases, it is your responsibility to verify that the transaction succeeded and was finalized by the cluster.

Note: Each transaction contains a recent blockhash to indicate its liveness.&#x20;

It is critical to wait until this blockhash expires before retrying a withdrawal transfer that does not appear to have been confirmed or finalized by the cluster.&#x20;

Otherwise, you risk a double spend. See more on blockhash expiration below.

First, get a recent blockhash using the getFees endpoint or the CLI command:

```
put fees --url http://localhost:8899
```

In the command-line tool, pass the --no-wait argument to send a transfer asynchronously, and include your recent blockhash with the --blockhash argument:

PUT transfer \<USER\_ADDRESS> --no-wait --allow-unfunded-recipient --blockhash \<RECENT\_BLOCKHASH> --keypair --url <http://localhost:8899> You can also build, sign, and serialize the transaction manually, and fire it off to the cluster using the JSON-RPC sendTransaction endpoint.

Transaction Confirmations & Finality#

Get the status of a batch of transactions using the getSignatureStatuses JSON-RPC endpoint.&#x20;

The confirmations field reports how many confirmed blocks have elapsed since the transaction was processed. If confirmations: null, it is finalized.

```
curl localhost:8899 -X POST -H "Content-Type: application/json" -d '{
  "jsonrpc":"2.0",
  "id":1,
  "method":"getSignatureStatuses",
  "params":[
    [
      "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
      "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"
    ]
  ]
}'

# Result
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 82
    },
    "value": [
      {
        "slot": 72,
        "confirmations": 10,
        "err": null,
        "status": {
          "Ok": null
        }
      },
      {
        "slot": 48,
        "confirmations": null,
        "err": null,
        "status": {
          "Ok": null
        }
      }
    ]
  },
  "id": 1
}
```

Blockhash Expiration#

You can check whether a particular blockhash is still valid by sending a getFeeCalculatorForBlockhash request with the blockhash as a parameter. If the response value is null, the blockhash is expired, and the withdrawal transaction using that blockhash should never succeed.

### Validating User-supplied Account Addresses for Withdrawals

As withdrawals are irreversible, it may be a good practice to validate a user-supplied account address before authorizing a withdrawal in order to prevent accidental loss of user funds.

Basic verification#

PUT addresses a 32-byte array, encoded with the bitcoin base58 alphabet. This results in an ASCII text string matching the following regular expression:

```
[1-9A-HJ-NP-Za-km-z]{32,44}
```

This check is insufficient on its own as PUT addresses are not checksummed, so typos cannot be detected. To further validate the user's input, the string can be decoded and the resulting byte array's length confirmed to be 32.&#x20;

However, there are some addresses that can decode to 32 bytes despite a typo such as a single missing character, reversed characters and ignored case

Advanced verification#

Due to the vulnerability to typos described above, it is recommended that the balance be queried for candidate withdraw addresses and the user prompted to confirm their intentions if a non-zero balance is discovered.

Valid ed25519 pubkey check#

The address of a normal account in PUT is a Base58-encoded string of a 256-bit ed25519 public key.&#x20;

Not all bit patterns are valid public keys for the ed25519 curve, so it is possible to ensure user-supplied account addresses are at least correct ed25519 public keys.

Java#

Here is a Java example of validating a user-supplied address as a valid ed25519 public key:

The following code sample assumes you're using the Maven.

pom.xml:

```
<repositories>
  ...
  <repository>
    <id>spring</id>
    <url>https://repo.spring.io/libs-release/</url>
  </repository>
</repositories>

...

<dependencies>
  ...
  <dependency>
      <groupId>io.github.novacrypto</groupId>
      <artifactId>Base58</artifactId>
      <version>0.1.3</version>
  </dependency>
  <dependency>
      <groupId>cafe.cryptography</groupId>
      <artifactId>curve25519-elisabeth</artifactId>
      <version>0.1.0</version>
  </dependency>
<dependencies>



import io.github.novacrypto.base58.Base58;
import cafe.cryptography.curve25519.CompressedEdwardsY;

public class PubkeyValidator
{
    public static boolean verifyPubkey(String userProvidedPubkey)
    {
        try {
            return _verifyPubkeyInternal(userProvidedPubkey);
        } catch (Exception e) {
            return false;
        }
    }

    public static boolean _verifyPubkeyInternal(String maybePubkey) throws Exception
    {
        byte[] bytes = Base58.base58Decode(maybePubkey);
        return !(new CompressedEdwardsY(bytes)).decompress().isSmallOrder();
    }
}
```

## Minimum Deposit & Withdrawal Amounts

Every deposit and withdrawal of PUT must be greater or equal to the minimum rent-exempt balance for the account at the wallet address (a basic PUT account holding no data), currently: 0.000890880 PUT

Similarly, every deposit account must contain at least this balance.

```
curl localhost:8899 -X POST -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "getMinimumBalanceForRentExemption",
  "params": [0]
}'

# Result
{"jsonrpc":"2.0","result":890880,"id":1}
```

## Supporting the PPL Token Standard

PPL Token is the standard for wrapped/synthetic token creation and exchange on the PUT blockchain.

The PPL Token workflow is similar to that of native PUT tokens, but there are a few differences which will be discussed in this section.

### Token Mints

Each type of PPL Token is declared by creating a mint account. This account stores metadata describing token features like the supply, number of decimals, and various authorities with control over the mint.&#x20;

Each PPL Token account references its associated mint and may only interact with PPL Tokens of that type.

### Installing the PPL-token CLI Tool

PPL Token accounts are queried and modified using the PPL-token command line utility.&#x20;

The examples provided in this section depend upon having it installed on the local system.

PPL-token is distributed from Rust crates.io via the Rust cargo command line utility.&#x20;

The latest version of cargo can be installed using a handy one-liner for your platform at rustup.rs.&#x20;

Once cargo is installed, PPL-token can be obtained with the following command:

```
cargo install PPL-token-cli
```

You can then check the installed version to verify

```
PPL-token --version
```

Which should result in something like

```
PPL-token-cli 2.0.1
```

### Account Creation

PPL Token accounts carry additional requirements that native System Program accounts do not:

* PPL Token accounts must be created before an amount of tokens can be deposited.&#x20;

&#x20;   Token accounts can be created explicitly with the PPL-token create-account command, or implicitly by the PPL-token transfer --fund-recipient ... command.

* PPL Token accounts must remain rent-exempt for the duration of their existence and therefore require a small amount of native PUT tokens be deposited at account creation.&#x20;

&#x20;   For PPL Token v2 accounts, this amount is 0.00203928 PUT (2,039,280 lamports).

### Command Line\#

To create an PPL Token account with the following properties:

* 1.Associated with the given mint
* 2.Owned by the funding account's keypair

  PPL-token create-account \<TOKEN\_MINT\_ADDRESS>

Example#

```
$ PPL-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir
Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV
Signature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7
```

Or to create an PPL Token account with a specific keypair:

```
$ put-keygen new -o token-account.json
$ PPL-token create-account AkUFCWTXb3w9nY2n6SFJvBV6VwvFUCe4KBMCcgLsa2ir token-account.json
Creating account 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV
Signature: 4JsqZEPra2eDTHtHpB4FMWSfk3UgcCVmkKkP7zESZeMrKmFFkDkNd91pKP3vPVVZZPiu5XxyJwS73Vi5WsZL88D7
```

### Checking an Account's Balance\#

Command Line

```
PPL-token balance <TOKEN_ACCOUNT_ADDRESS>
```

Example#

```
$ put balance 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV
0
```

### Token Transfers

The source account for a transfer is the actual token account that contains the amount.

The recipient address however can be a normal wallet account.

&#x20;If an associated token account for the given mint does not yet exist for that wallet, the transfer will create it provided that the --fund-recipient argument as provided.

### Command Line

```
PPL-token transfer <SENDER_ACCOUNT_ADDRESS> <AMOUNT> <RECIPIENT_WALLET_ADDRESS> --fund-recipient
```

Example#

```
$ PPL-token transfer 6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BN 1 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV
Transfer 1 tokens
  Sender: 6B199xxzw3PkAm25hGJpjj3Wj3WNYNHzDAnt1tEqg5BN
  Recipient: 6VzWGL51jLebvnDifvcuEDec17sK6Wupi4gYhm5RzfkV
Signature: 3R6tsog17QM8KfzbcbdP4aoMfwgo6hBggJDVy7dZPVmH2xbCWjEj31JKD53NzMrf25ChFjY7Uv2dfCDq4mGFFyAj
```

### Depositing

Since each (wallet, mint) pair requires a separate account on chain.&#x20;

It is recommended that the addresses for these accounts be derived from PUT deposit wallets using the Associated Token Account (ATA) scheme and that only deposits from ATA addresses be accepted.

Monitoring for deposit transactions should follow the block polling method described above.&#x20;

Each new block should be scanned for successful transactions referencing user token-account derived addresses.&#x20;

The preTokenBalance and postTokenBalance fields from the transaction's metadata must then be used to determine the effective balance change.&#x20;

These fields will identify the token mint and account owner (main wallet address) of the affected account.

Note that if a receiving account is created during the transaction, it will have no preTokenBalance entry as there is no existing account state.&#x20;

In this case, the initial balance can be assumed to be zero.

Withdrawing#

The withdrawal address a user provides must be the that of their PUT wallet.

Before executing a withdrawal transfer, the exchange should check the address as described above.&#x20;

Additionally this address must be owned by the System Program and have no account data.&#x20;

If the address has no PUT balance, user confirmation should be obtained before proceeding with the withdrawal. All other withdrawal addresses must be rejected.

From the withdrawal address, the Associated Token Account (ATA) for the correct mint is derived and the transfer issued to that account via a TransferChecked instruction.&#x20;

Note that it is possible that the ATA address does not yet exist, at which point the exchange should fund the account on behalf of the user. For PPL Token v2 accounts, funding the withdrawal account will require 0.00203928 PUT (2,039,280 lamports).

Template PPL-token transfer command for a withdrawal:

```
$ PPL-token transfer --fund-recipient <exchange token account> <withdrawal amount> <withdrawal address>
```

### Other Considerations

### Freeze Authority

For regulatory compliance reasons, an PPL Token issuing entity may optionally choose to hold "Freeze Authority" over all accounts created in association with its mint.&#x20;

This allows them to freeze the assets in a given account at will, rendering the account unusable until thawed. If this feature is in use, the freeze authority's pubkey will be registered in the PPL Token's mint account.

## Testing the Integration

Be sure to test your complete workflow on PUT devnet and testnet clusters before moving to production on mainnet-beta.&#x20;

Devnet is the most open and flexible, and ideal for initial development, while testnet offers more realistic cluster configuration.&#x20;

Both devnet and testnet support a faucet, run PUT airdrop 1 to obtain some devnet or testnet PUT for development and testing.


# Retrying Transactions

Retrying Transactions

On some occasions, a seemingly valid transaction may be dropped before it is included in a block.&#x20;

This most often occurs during periods of network congestion, when an RPC node fails to rebroadcast the transaction to the leader.&#x20;

To an end-user, it may appear as if their transaction disappears entirely.&#x20;

While RPC nodes are equipped with a generic rebroadcasting algorithm, application developers are also capable of developing their own custom rebroadcasting logic.

## Facts

NOTE

Fact Sheet

* RPC nodes will attempt to rebroadcast transactions using a generic algorithm
* Application developers can implement their own custom rebroadcasting logic
* Developers should take advantage of the maxRetries parameter on the sendTransaction JSON-RPC method
* Developers should enable preflight checks to raise errors before transactions are submitted
* Before re-signing any transaction, it is very important to ensure that the initial transaction’s blockhash has expired

## The Journey of a Transaction

### How Clients Submit Transactions

In PUT, there is no concept of a mempool. All transactions, whether they are initiated programmatically or by an end-user, are efficiently routed to leaders so that they can be processed into a block. There are two main ways in which a transaction can be sent to leaders:

* 1.By proxy via an RPC server and the sendTransaction JSON-RPC method
* 2.Directly to leaders via a TPU Client

The vast majority of end-users will submit transactions via an RPC server.&#x20;

When a client submits a transaction, the receiving RPC node will in turn attempt to broadcast the transaction to both the current and next leaders.&#x20;

Until the transaction is processed by a leader, there is no record of the transaction outside of what the client and the relaying RPC nodes are aware of.&#x20;

In the case of a TPU client, rebroadcast and leader forwarding is handled entirely by the client software.

<figure><img src="/files/AH14HgaQAX1fCk22Ytm4" alt=""><figcaption></figcaption></figure>

### How RPC Nodes Broadcast Transaction

After an RPC node receives a transaction via sendTransaction, it will convert the transaction into a UDP packet before forwarding it to the relevant leaders.&#x20;

UDP allows validators to quickly communicate with one another, but does not provide any guarantees regarding transaction delivery.

Because PUT’s leader schedule is known in advance of every epoch (\~2 days), an RPC node will broadcast its transaction directly to the current and next leaders.&#x20;

This is in contrast to other gossip protocols such as Ethereum that propagate transactions randomly and broadly across the entire network.&#x20;

By default, RPC nodes will try to forward transactions to leaders every two seconds until either the transaction is finalized or the transaction’s blockhash expires (150 blocks or \~1 minute 19 seconds as of the time of this writing).&#x20;

If the outstanding rebroadcast queue size is greater than 10,000 transactions, newly submitted transactions are dropped.&#x20;

There are command-line arguments that RPC operators can adjust to change the default behavior of this retry logic.

When an RPC node broadcasts a transaction, it will attempt to forward the transaction to a leader’s Transaction Processing Unit (TPU).&#x20;

The TPU processes transactions in five distinct phases:

* Fetch Stage
* SigVerify Stage
* Banking Stage
* Proof of History Service
* Broadcast Stage

<figure><img src="/files/rTd61mvepYx8c6QOVl4D" alt=""><figcaption></figcaption></figure>

Of these five phases, the Fetch Stage is responsible for receiving transactions. Within the Fetch Stage, validators will categorize incoming transactions according to three ports:

* tpu handles regular transactions such as token transfers, NFT mints, and program instructions
* tpu\_vote focuses exclusively on voting transactions
* tpu\_forwards forwards unprocessed packets to the next leader if the current leader is unable to process all transactions

For more information on the TPU, please refer to this excellent writeup by Jito Labs.

## How Transactions Get Dropped

Throughout a transaction’s journey, there are a few scenarios in which the transaction can be unintentionally dropped from the network.

### Before a transaction is processed

If the network drops a transaction, it will most likely do so before the transaction is processed by a leader.&#x20;

UDP packet loss is the simplest reason why this might occur.&#x20;

During times of intense network load, it’s also possible for validators to become overwhelmed by the sheer number of transactions required for processing.&#x20;

While validators are equipped to forward surplus transactions via tpu\_forwards, there is a limit to the amount of data that can be forwarded.

Furthermore, each forward is limited to a single hop between validators.&#x20;

That is, transactions received on the tpu\_forwards port are not forwarded on to other validators.

There are also two lesser known reasons why a transaction may be dropped before it is processed.&#x20;

The first scenario involves transactions that are submitted via an RPC pool. Occasionally, part of the RPC pool can be sufficiently ahead of the rest of the pool.&#x20;

This can cause issues when nodes within the pool are required to work together. In this example, the transaction’s recentBlockhash is queried from the advanced part of the pool (Backend A).&#x20;

When the transaction is submitted to the lagging part of the pool (Backend B), the nodes will not recognize the advanced blockhash and will drop the transaction.&#x20;

This can be detected upon transaction submission if developers enable preflight checks on sendTransaction.

<figure><img src="/files/qKyOamocO6CTyZzFa6sm" alt=""><figcaption></figcaption></figure>

Temporarily network forks can also result in dropped transactions.&#x20;

If a validator is slow to replay its blocks within the Banking Stage, it may end up creating a minority fork.&#x20;

When a client builds a transaction, it’s possible for the transaction to reference a recentBlockhash that only exists on the minority fork.&#x20;

After the transaction is submitted, the cluster can then switch away from its minority fork before the transaction is processed. In this scenario, the transaction is dropped due to the blockhash not being found.

<figure><img src="/files/VqDY4k4tc8pa7owYvq97" alt=""><figcaption></figcaption></figure>

### After a transaction is processed and before it is finalized\#

In the event a transaction references a recentBlockhash from a minority fork, it’s still possible for the transaction to be processed.

&#x20;In this case, however, it would be processed by the leader on the minority fork.&#x20;

When this leader attempts to share its processed transactions with the rest of the network, it would fail to reach consensus with the majority of validators that do not recognize the minority fork.&#x20;

At this time, the transaction would be dropped before it could be finalized.

<figure><img src="/files/2z3kKtUpzMmuFarBz64u" alt=""><figcaption></figcaption></figure>

## Handling Dropped Transactions

While RPC nodes will attempt to rebroadcast transactions, the algorithm they employ is generic and often ill-suited for the needs of specific applications.&#x20;

To prepare for times of network congestion, application developers should customize their own rebroadcasting logic.

### An In-Depth Look at sendTransaction

When it comes to submitting transactions, the sendTransaction RPC method is the primary tool available to developers. sendTransaction is only responsible for relaying a transaction from a client to an RPC node.

&#x20;If the node receives the transaction, sendTransaction will return the transaction id that can be used to track the transaction.&#x20;

A successful response does not indicate whether the transaction will be processed or finalized by the cluster.

NOTE

Request Parameters#

* transaction: string - fully-signed Transaction, as encoded string
* (optional) configuration object: object
  * skipPreflight: boolean - if true, skip the preflight transaction checks (default: false)
  * (optional) preflightCommitment: string - Commitment level to use for preflight simulations against the bank slot (default: "finalized").
  * (optional) encoding: string - Encoding used for the transaction data. Either "base58" (slow), or "base64". (default: "base58").
  * (optional) maxRetries: usize - Maximum number of times for the RPC node to retry sending the transaction to the leader. If this parameter is not provided, the RPC node will retry the transaction until it is finalized or until the blockhash expires.

Response

* transaction id: string - First transaction signature embedded in the transaction, as base-58 encoded string. This transaction id can be used with getSignatureStatuses to poll for status updates.

## Customizing Rebroadcast Logic

In order to develop their own rebroadcasting logic, developers should take advantage of sendTransaction’s maxRetries parameter.&#x20;

If provided, maxRetries will override an RPC node’s default retry logic, allowing developers to manually control the retry process within reasonable bounds.

A common pattern for manually retrying transactions involves temporarily storing the lastValidBlockHeight that comes from getLatestBlockhash.&#x20;

Once stashed, an application can then poll the cluster’s blockheight and manually retry the transaction at an appropriate interval.&#x20;

In times of network congestion, it’s advantageous to set maxRetries to 0 and manually rebroadcast via a custom algorithm.&#x20;

While some applications may employ an exponential backoff algorithm, others such as Mango opt to continuously resubmit transactions at a constant interval until some timeout has occurred.

```
import {
  Keypair,
  Connection,
  LAMPORTS_PER_SOL,
  SystemProgram,
  Transaction,
} from "@put/web3.js";
import * as nacl from "tweetnacl";

const sleep = async (ms: number) => {
  return new Promise((r) => setTimeout(r, ms));
};

(async () => {
  const payer = Keypair.generate();
  const toAccount = Keypair.generate().publicKey;

  const connection = new Connection("http://127.0.0.1:8899", "confirmed");

  const airdropSignature = await connection.requestAirdrop(
    payer.publicKey,
    LAMPORTS_PER_SOL,
  );

  await connection.confirmTransaction({ signature: airdropSignature });

  const blockhashResponse = await connection.getLatestBlockhashAndContext();
  const lastValidBlockHeight = blockhashResponse.context.slot + 150;

  const transaction = new Transaction({
    feePayer: payer.publicKey,
    blockhash: blockhashResponse.value.blockhash,
    lastValidBlockHeight: lastValidBlockHeight,
  }).add(
    SystemProgram.transfer({
      fromPubkey: payer.publicKey,
      toPubkey: toAccount,
      lamports: 1000000,
    }),
  );
  const message = transaction.serializeMessage();
  const signature = nacl.sign.detached(message, payer.secretKey);
  transaction.addSignature(payer.publicKey, Buffer.from(signature));
  const rawTransaction = transaction.serialize();
  let blockheight = await connection.getBlockHeight();

  while (blockheight < lastValidBlockHeight) {
    connection.sendRawTransaction(rawTransaction, {
      skipPreflight: true,
    });
    await sleep(500);
    blockheight = await connection.getBlockHeight();
  }
})();
```

When polling via getLatestBlockhash, applications should specify their intended commitment level.&#x20;

By setting its commitment to confirmed (voted on) or finalized (\~30 blocks after confirmed), an application can avoid polling a blockhash from a minority fork.

If an application has access to RPC nodes behind a load balancer, it can also choose to divide its workload amongst specific nodes.

&#x20;RPC nodes that serve data-intensive requests such as getProgramAccounts may be prone to falling behind and can be ill-suited for also forwarding transactions.&#x20;

For applications that handle time-sensitive transactions, it may be prudent to have dedicated nodes that only handle sendTransaction.

### The Cost of Skipping Preflight

By default, sendTransaction will perform three preflight checks prior to submitting a transaction. Specifically, sendTransaction will:

* Verify that all signatures are valid
* Check that the referenced blockhash is within the last 150 blocks
* Simulate the transaction against the bank slot specified by the preflightCommitment

In the event that any of these three preflight checks fail, sendTransaction will raise an error prior to submitting the transaction.&#x20;

Preflight checks can often be the difference between losing a transaction and allowing a client to gracefully handle an error.&#x20;

To ensure that these common errors are accounted for, it is recommended that developers keep skipPreflight set to false.

### When to Re-Sign Transactions

Despite all attempts to rebroadcast, there may be times in which a client is required to re-sign a transaction.&#x20;

Before re-signing any transaction, it is very important to ensure that the initial transaction’s blockhash has expired.&#x20;

If the initial blockhash is still valid, it is possible for both transactions to be accepted by the network. To an end-user, this would appear as if they unintentionally sent the same transaction twice.

In PUT, a dropped transaction can be safely discarded once the blockhash it references is older than the lastValidBlockHeight received from getLatestBlockhash.

&#x20;Developers should keep track of this lastValidBlockHeight by querying getEpochInfo and comparing with blockHeight in the response.&#x20;

Once a blockhash is invalidated, clients may re-sign with a newly-queried blockhash.


# Library


# Introduction

The PUT Program Library (PPL) is a collection of on-chain programs targeting the Sealevel parallel runtime.&#x20;

These programs are tested against PUT's implementation of Sealevel, put-runtime, and deployed to its mainnet.&#x20;

As others implement Sealevel, we will graciously accept patches to ensure the programs here are portable across all implementations.


# Token Program

Token Program A Token program on the PUT blockchain.

This program defines a common implementation for Fungible and Non Fungible tokens.

## Source&#x20;

The Token Program's source is available on github

## Interface&#x20;

The Token Program is written in Rust and available on crates.io and docs.rs.

Auto-generated C bindings are also available here

JavaScript bindings are available that support loading the Token Program on to a chain and issue instructions.

See the PPL Associated Token Account program for convention around wallet address to token account mapping and funding.

## Reference Guide

### Setup

{% tabs %}
{% tab title="CLI" %}
The ppl-token command-line utility can be used to experiment with PPL tokens. Once you have Rust installed, run:

```
$ cargo install ppl-token-cli
```

Run ppl-token --help for a full description of available commands.

### Configuration

The ppl-token configuration is shared with the PUT command-line tool.

Current Configuration

```
$ put config get
Config File: ${HOME}/.config/put/cli/config.yml
RPC URL: https://rpc.putdev.com:8889
WebSocket URL: wss://rpc.putdev.com:8889 (computed)
Keypair Path: ${HOME}/.config/put/id.json
```

Cluster RPC URL

See PUT clusters for cluster-specific RPC URLs

```
$ put config set --url https://rpc.putdev.com:8889
```

Default Keypair

See Keypair conventions for information on how to setup a keypair if you don't already have one.

Keypair File

```
$ put config set --keypair ${HOME}/new-keypair.json
```

Hardware Wallet URL (See URL spec)

```
$ put config set --keypair usb://ledger/
```

{% endtab %}

{% tab title="JS" %}
Yarn

```
yarn add @put/ppl-token
```

npm

```
npm install @put/ppl-token
```

### Configuration&#x20;

You can connect to different clusters using Connection in @put/web3.js

```
const web3 = require('@put/web3.js');
const connection = new web3.Connection(web3.clusterApiUrl('devnet'), 'confirmed');
```

### Keypair

You can either get your keypair using Keypair from @put/web3.js, or let the user's wallet handle the keypair and use sendTransaction from wallet-adapter
{% endtab %}
{% endtabs %}

### Airdrop PUT&#x20;

Creating tokens and accounts requires PUT for account rent deposits and transaction fees. If the cluster you are targeting offers a faucet, you can get a little PUT for testing:

{% tabs %}
{% tab title="CLI" %}

```
$ put airdrop 1
```

{% endtab %}

{% tab title="JS" %}

```
import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_PUT } from '@put/web3.js';

const payer = Keypair.generate();

const connection = new Connection(
  clusterApiUrl('devnet'),
  'confirmed'
);

const airdropSignature = await connection.requestAirdrop(
  payer.publicKey,
  LAMPORTS_PER_PUT,
);

await connection.confirmTransaction(airdropSignature);
```

###

{% endtab %}
{% endtabs %}

### Example: Creating your own fungible token

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token create-token
Creating token AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Signature: 47hsLFxWRCg8azaZZPSnQR8DNTRsGyPNfUK7jqyzgt7wf9eag3nSnewqoZrVZHKm8zt3B6gzxhr91gdQ5qYrsRG4
```

{% endtab %}

{% tab title="JS" %}

```
 import { createMint } from '@put/ppl-token'; 
 import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_PUT } from '@put/web3.js';
 
 const payer = Keypair.generate();
const mintAuthority = Keypair.generate();
const freezeAuthority = Keypair.generate();

const connection = new Connection(
  clusterApiUrl('devnet'),
  'confirmed'
);

const mint = await createMint(
  connection,
  payer,
  mintAuthority.publicKey,
  freezeAuthority.publicKey,
  9 // We are using 9 to match the CLI decimal default exactly
);

console.log(mint.toBase58());
// AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
```

{% endtab %}
{% endtabs %}

The unique identifier of the token is AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM.

Tokens when initially created by ppl-token have no supply:

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token supply AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
0
```

{% endtab %}

{% tab title="JS" %}

```
const mintInfo = await getMint(
  connection,
  mint
)

console.log(mintInfo.supply);
// 0
```

{% endtab %}
{% endtabs %}

Let's mint some.

&#x20;First create an account to hold a balance of the new AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM token:

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token create-account AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
Creating account 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Signature: 42Sa5eK9dMEQyvD9GMHuKxXf55WLZ7tfjabUKDhNoZRAxj9MsnN7omriWMEHXLea3aYpjZ862qocRLVikvkHkyfy
```

{% endtab %}

{% tab title="JS" %}

```
const tokenAccount = await getOrCreateAssociatedTokenAccount(
  connection,
  payer,
  mint,
  payer.publicKey
)

console.log(tokenAccount.address.toBase58());
// 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
```

{% endtab %}
{% endtabs %}

7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi is now an empty account:

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token balance AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
0
```

{% endtab %}

{% tab title="JS" %}

```
const tokenAccountInfo = await getAccount(
  connection,
  tokenAccount.address
)

console.log(tokenAccountInfo.amount);
// 0
```

{% endtab %}
{% endtabs %}

Mint 100 tokens into the account:

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token mint AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 100
Minting 100 tokens
  Token: AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
  Recipient: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
Signature: 41mARH42fPkbYn1mvQ6hYLjmJtjW98NXwd6pHqEYg9p8RnuoUsMxVd16RkStDHEzcS2sfpSEpFscrJQn3HkHzLaa
```

{% endtab %}

{% tab title="JS" %}

```
await mintTo(
  connection,
  payer,
  mint,
  tokenAccount.address,
  mintAuthority,
  100000000000 // because decimals for the mint are set to 9 
)
```

{% endtab %}
{% endtabs %}

The token supply and account balance now reflect the result of minting:

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token supply AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
100

$ ppl-token balance AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM
100  
```

{% endtab %}

{% tab title="JS" %}

```
const mintInfo = await getMint(
  connection,
  mint
)

console.log(mintInfo.supply);
// 100

const tokenAccountInfo = await getAccount(
  connection,
  tokenAccount.address
)

console.log(tokenAccountInfo.amount);
// 100
```

{% endtab %}
{% endtabs %}

### Example: View all Tokens that you own

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token accounts
Token                                         Balance
------------------------------------------------------------
7e2X5oeAAJyUTi4PfSGXFLGhyPw2H8oELm1mx87ZCgwF  84
AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  100
AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  0    (Aux-1*)
AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  1    (Aux-2*)
```

{% endtab %}

{% tab title="JS" %}

```
import {AccountLayout, TOKEN_PROGRAM_ID} from "@put/ppl-token";
import {clusterApiUrl, Connection, PublicKey} from "@put/web3.js";

(async () => {

  const connection = new Connection(clusterApiUrl('devnet'), 'confirmed');

  const tokenAccounts = await connection.getTokenAccountsByOwner(
    new PublicKey('8YLKoCu7NwqHNS8GzuvA2ibsvLrsg22YMfMDafxh1B15'),
    {
      programId: TOKEN_PROGRAM_ID,
    }
  );

  console.log("Token                                         Balance");
  console.log("------------------------------------------------------------");
  tokenAccounts.value.forEach((tokenAccount) => {
    const accountData = AccountLayout.decode(tokenAccount.account.data);
    console.log(`${new PublicKey(accountData.mint)}   ${accountData.amount}`);
  })

})();

/*
Token                                         Balance
------------------------------------------------------------
7e2X5oeAAJyUTi4PfSGXFLGhyPw2H8oELm1mx87ZCgwF  84
AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  100
AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  0
AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  1
*/
```

{% endtab %}
{% endtabs %}

### Example: Wrapping PUT in a Token&#x20;

When you want to wrap PUT, you can send PUT to an associated token account on the native mint and call syncNative. syncNative updates the amount field on the token account to match the amount of wrapped PUT available.&#x20;

That PUT is only retrievable by closing the token account and choosing the desired address to send the token account's lamports.

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token wrap 1
Wrapping 1 PUT into GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
Signature: 4f4s5QVMKisLS6ihZcXXPbiBAzjnvkBcp2A7KKER7k9DwJ4qjbVsQBKv2rAyBumXC1gLn8EJQhwWkybE4yJGnw2Y
```

{% endtab %}

{% tab title="JS" %}

```
import {NATIVE_MINT, createAssociatedTokenAccountInstruction, getAssociatedTokenAddress, createSyncNativeInstruction, getAccount} from "@put/ppl-token";
import {clusterApiUrl, Connection, Keypair, LAMPORTS_PER_PUT, SystemProgram, Transaction, sendAndConfirmTransaction} from "@put/web3.js";

(async () => {

const connection = new Connection(clusterApiUrl('devnet'), 'confirmed');

const wallet = Keypair.generate();

const airdropSignature = await connection.requestAirdrop(
  wallet.publicKey,
  2 * LAMPORTS_PER_PUT,
);

await connection.confirmTransaction(airdropSignature);

const associatedTokenAccount = await getAssociatedTokenAddress(
  NATIVE_MINT,
  wallet.publicKey
)

// Create token account to hold your wrapped PUT
const ataTransaction = new Transaction()
  .add(
    createAssociatedTokenAccountInstruction(
      wallet.publicKey,
      associatedTokenAccount,
      wallet.publicKey,
      NATIVE_MINT
    )
  );

await sendAndConfirmTransaction(connection, ataTransaction, [wallet]);

// Transfer PUT to associated token account and use SyncNative to update wrapped PUT balance
const solTransferTransaction = new Transaction()
  .add(
    SystemProgram.transfer({
        fromPubkey: wallet.publicKey,
        toPubkey: associatedTokenAccount,
        lamports: LAMPORTS_PER_PUT
      }),
      createSyncNativeInstruction(
        associatedTokenAccount
    )
  )

await sendAndConfirmTransaction(connection, solTransferTransaction, [wallet]);

const accountInfo = await getAccount(connection, associatedTokenAccount);

console.log(`Native: ${accountInfo.isNative}, Lamports: ${accountInfo.amount}`);

})();
```

{% endtab %}
{% endtabs %}

To unwrap the Token back to PUT:

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token unwrap GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
Unwrapping GJTxcnA5Sydy8YRhqvHxbQ5QNsPyRKvzguodQEaShJje
  Amount: 1 PUT
  Recipient: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
Signature: f7opZ86ZHKGvkJBQsJ8Pk81v8F3v1VUfyd4kFs4CABmfTnSZK5BffETznUU3tEWvzibgKJASCf7TUpDmwGi8Rmh
```

{% endtab %}

{% tab title="JS" %}

```
const walletBalance = await connection.getBalance(wallet.publicKey);

console.log(`Balance before unwrapping 1 WPUT: ${walletBalance}`)

await closeAccount(connection, wallet, associatedTokenAccount, wallet.publicKey, wallet);

const walletBalancePostClose = await connection.getBalance(wallet.publicKey);

console.log(`Balance after unwrapping 1 WPUT: ${walletBalancePostClose}`)

/*
Balance before unwrapping 1 WPUT: 997950720
Balance after unwrapping 1 WPUT: 1999985000
*/
```

{% endtab %}
{% endtabs %}

Note: Some lamports were removed for transaction fees

### Example: Transferring tokens to another user

First the receiver uses ppl-token create-account to create their associated token account for the Token type.&#x20;

Then the receiver obtains their wallet address by running PUT address and provides it to the sender.

The sender then runs:

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token transfer AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50 vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
Transfer 50 tokens
  Sender: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
  Recipient: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
  Recipient associated token account: F59618aQB8r6asXeMcB9jWuY6NEx1VduT9yFo1GTi1ks

Signature: 5a3qbvoJQnTAxGPHCugibZTbSu7xuTgkxvF4EJupRjRXGgZZrnWFmKzfEzcqKF2ogCaF4QKVbAtuFx7xGwrDUcGd
```

{% endtab %}

{% tab title="JS" %}

```
import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_PUT } from '@put/web3.js';
import { createMint, getOrCreateAssociatedTokenAccount, mintTo, transfer } from '@put/ppl-token';

(async () => {
    // Connect to cluster
    const connection = new Connection(clusterApiUrl('devnet'), 'confirmed');

    // Generate a new wallet keypair and airdrop PUT
    const fromWallet = Keypair.generate();
    const fromAirdropSignature = await connection.requestAirdrop(fromWallet.publicKey, LAMPORTS_PER_PUT);

    // Wait for airdrop confirmation
    await connection.confirmTransaction(fromAirdropSignature);

    // Generate a new wallet to receive newly minted token
    const toWallet = Keypair.generate();

    // Create new token mint
    const mint = await createMint(connection, fromWallet, fromWallet.publicKey, null, 9);

    // Get the token account of the fromWallet address, and if it does not exist, create it
    const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
        connection,
        fromWallet,
        mint,
        fromWallet.publicKey
    );

    // Get the token account of the toWallet address, and if it does not exist, create it
    const toTokenAccount = await getOrCreateAssociatedTokenAccount(connection, fromWallet, mint, toWallet.publicKey);

    // Mint 1 new token to the "fromTokenAccount" account we just created
    let signature = await mintTo(
        connection,
        fromWallet,
        mint,
        fromTokenAccount.address,
        fromWallet.publicKey,
        1000000000
    );
    console.log('mint tx:', signature);

    // Transfer the new token to the "toTokenAccount" we just created
    signature = await transfer(
        connection,
        fromWallet,
        fromTokenAccount.address,
        toTokenAccount.address,
        fromWallet.publicKey,
        50
    );
})();
```

{% endtab %}
{% endtabs %}

### Example: Transferring tokens to another user, with sender-funding&#x20;

If the receiver does not yet have an associated token account, the sender may choose to fund the receiver's account.

The receiver obtains their wallet address by running put address and provides it to the sender.

The sender then runs to fund the receiver's associated token account, at the sender's expense, and then transfers 50 tokens into it:

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token transfer --fund-recipient AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50 vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
Transfer 50 tokens
  Sender: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
  Recipient: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
  Recipient associated token account: F59618aQB8r6asXeMcB9jWuY6NEx1VduT9yFo1GTi1ks
  Funding recipient: F59618aQB8r6asXeMcB9jWuY6NEx1VduT9yFo1GTi1ks (0.00203928 PUT)

Signature: 5a3qbvoJQnTAxGPHCugibZTbSu7xuTgkxvF4EJupRjRXGgZZrnWFmKzfEzcqKF2ogCaF4QKVbAtuFx7xGwrDUcGd
```

{% endtab %}

{% tab title="JS" %}

```
const signature = await transfer(
    connection,
    toWallet,
    fromTokenAccount.address,
    toTokenAccount.address,
    fromWallet.publicKey,
    50,
    [fromWallet, toWallet]
);
```

{% endtab %}
{% endtabs %}

### Example: Transferring tokens to an explicit recipient token account&#x20;

Tokens may be transferred to a specific recipient token account.&#x20;

The recipient token account must already exist and be of the same Token type.

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token create-account AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM /path/to/auxiliary_keypair.json
Creating account CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ
Signature: 4yPWj22mbyLu5mhfZ5WATNfYzTt5EQ7LGzryxM7Ufu7QCVjTE7czZdEBqdKR7vjKsfAqsBdjU58NJvXrTqCXvfWW

$ ppl-token accounts AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM -v
Account                                       Token                                         Balance
--------------------------------------------------------------------------------------------------------
7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi  AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  100
CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ  AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  0    (Aux-1*)

$ ppl-token transfer AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM 50 CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ
Transfer 50 tokens
  Sender: 7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi
  Recipient: CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ

Signature: 5a3qbvoJQnTAxGPHCugibZTbSu7xuTgkxvF4EJupRjRXGgZZrnWFmKzfEzcqKF2ogCaF4QKVbAtuFx7xGwrDUcGd

$ ppl-token accounts AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM -v
Account                                       Token                                         Balance
--------------------------------------------------------------------------------------------------------
7UX2i7SucgLMQcfZ75s3VXmZZY4YRUyJN9X1RgfMoDUi  AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  50
CqAxDdBRnawzx9q4PYM3wrybLHBhDZ4P6BTV13WsRJYJ  AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM  50  (Aux-1*)
```

{% endtab %}

{% tab title="JS" %}

```
import {getAccount, createMint, createAccount, mintTo, getOrCreateAssociatedTokenAccount, transfer} from "@put/ppl-token";
import {clusterApiUrl, Connection, Keypair, LAMPORTS_PER_PUT} from "@put/web3.js";

(async () => {

  const connection = new Connection(clusterApiUrl('devnet'), 'confirmed');

  const wallet = Keypair.generate();
  const auxiliaryKeypair = Keypair.generate();

  const airdropSignature = await connection.requestAirdrop(
    wallet.publicKey,
    LAMPORTS_PER_PUT,
  );

  await connection.confirmTransaction(airdropSignature);

  const mint = await createMint(
    connection,
    wallet,
    wallet.publicKey,
    wallet.publicKey,
    9
  );

  // Create custom token account
  const auxiliaryTokenAccount = await createAccount(
    connection,
    wallet,
    mint,
    wallet.publicKey,
    auxiliaryKeypair
  );

  const associatedTokenAccount = await getOrCreateAssociatedTokenAccount(
    connection,
    wallet,
    mint,
    wallet.publicKey
  );

  await mintTo(
    connection,
    wallet,
    mint,
    associatedTokenAccount.address,
    wallet,
    50
  );

  const accountInfo = await getAccount(connection, associatedTokenAccount.address);

  console.log(accountInfo.amount);
  // 50

  await transfer(
    connection,
    wallet,
    associatedTokenAccount.address,
    auxiliaryTokenAccount,
    wallet,
    50
  );

  const auxAccountInfo = await getAccount(connection, auxiliaryTokenAccount);

  console.log(auxAccountInfo.amount);
  // 50
})();
```

{% endtab %}
{% endtabs %}

### Multisig usage

{% tabs %}
{% tab title="CLI" %}
The main difference in ppl-token command line usage when referencing multisig accounts is in specifying the --owner argument. Typically the signer specified by this argument directly provides a signature granting its authority, but in the multisig case it just points to the address of the multisig account. Signatures are then provided by the multisig signer-set members specified by the --multisig-signer argument.

Multisig accounts can be used for any authority on an PPL Token mint or token account.

* Mint account mint authority:ppl-token mint ...,ppl-token authorize ... mint ...
* Mint account freeze authority:ppl-token freeze ...,ppl-token thaw ...,ppl-token authorize ... freeze ...
* Token account owner authority:ppl-token transfer ...,ppl-token approve ...,ppl-token revoke ...,ppl-token burn ...,ppl-token wrap ...,ppl-token unwrap ...,ppl-token authorize ... owner ...
* Token account close authority:ppl-token close ...,ppl-token authorize ... close ...
  {% endtab %}

{% tab title="JS" %}
The main difference in using multisign is specifying the owner as the multisig key, and giving the list of signers when contructing a transaction. Normally you would provide the signer that has authority to run the transaction as the owner, but in the multisig case the owner would be the multisig key.

Multisig accounts can be used for any authority on an PPL Token mint or token account.

* Mint account mint authority:createMint(/\* ... */, mintAuthority: multisigKey, /* ... \*/)
* Mint account freeze authority:createMint(/\* ... */, freezeAuthority: multisigKey, /* ... \*/)
* Token account owner authority:getOrCreateAssociatedTokenAccount(/\* ... */, mintAuthority: multisigKey, /* ... \*/)
* Token account close authority:closeAccount(/\* ... */, authority: multisigKey, /* ... \*/)
  {% endtab %}
  {% endtabs %}

### Example: Mint with multisig authority

First create keypairs to act as the multisig signer-set. In reality, these can be any supported signer, like: a Ledger hardware wallet, a keypair file, or a paper wallet. For convenience, generated keypairs will be used in this example.

{% tabs %}
{% tab title="CLI" %}

```
$ for i in $(seq 3); do put-keygen new --no-passphrase -so "signer-${i}.json"; done
Wrote new keypair to signer-1.json
Wrote new keypair to signer-2.json
Wrote new keypair to signer-3.json
```

{% endtab %}

{% tab title="JS" %}

```
const signer1 = Keypair.generate(); const signer2 = Keypair.generate(); const signer3 = Keypair.generate();
```

{% endtab %}
{% endtabs %}

In order to create the multisig account, the public keys of the signer-set must be collected.

{% tabs %}
{% tab title="CLI" %}

```
$ for i in $(seq 3); do SIGNER="signer-${i}.json"; echo "$SIGNER: $(put-keygen pubkey "$SIGNER")"; done
signer-1.json: BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ
signer-2.json: DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY
signer-3.json: D7ssXHrZJjfpZXsmDf8RwfPxe1BMMMmP1CtmX3WojPmG


```

{% endtab %}

{% tab title="JS" %}

```
console.log(signer1.publicKey.toBase58());
console.log(signer2.publicKey.toBase58());
console.log(signer3.publicKey.toBase58());
/*
  BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ
  DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY
  D7ssXHrZJjfpZXsmDf8RwfPxe1BMMMmP1CtmX3WojPmG
 */
 
```

{% endtab %}
{% endtabs %}

Now the multisig account can be created with the ppl-token create-multisig subcommand. Its first positional argument is the minimum number of signers (M) that must sign a transaction affecting a token/mint account that is controlled by this multisig account. The remaining positional arguments are the public keys of all keypairs allowed (N) to sign for the multisig account. This example will use a "2 of 3" multisig account. That is, two of the three allowed keypairs must sign all transactions.

NOTE: PPL Token Multisig accounts are limited to a signer-set of eleven signers (1 <= N <= 11) and minimum signers must be no more than N (1 <= M <= N)

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token create-multisig 2 BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ \
DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY D7ssXHrZJjfpZXsmDf8RwfPxe1BMMMmP1CtmX3WojPmG

Creating 2/3 multisig 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re
Signature: 2FN4KXnczAz33SAxwsuevqrD1BvikP6LUhLie5Lz4ETt594X8R7yvMZzZW2zjmFLPsLQNHsRuhQeumExHbnUGC9A
```

{% endtab %}

{% tab title="JS" %}

```
const multisigKey = await createMultisig(
  connection,
  payer,
  [
    signer1.publicKey,
    signer2.publicKey,
    signer3.publicKey
  ],
  2
);

console.log(`Created 2/3 multisig ${multisigKey.toBase58()}`);
// Created 2/3 multisig 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re
```

{% endtab %}
{% endtabs %}

Next create the token mint and receiving accounts as previously described and set the mint account's minting authority to the multisig account

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token create-token
Creating token 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Signature: 3n6zmw3hS5Hyo5duuhnNvwjAbjzC42uzCA3TTsrgr9htUonzDUXdK1d8b8J77XoeSherqWQM8mD8E1TMYCpksS2r

$ ppl-token create-account 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
Creating account EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC
Signature: 5mVes7wjE7avuFqzrmSCWneKBQyPAjasCLYZPNSkmqmk2YFosYWAP9hYSiZ7b7NKpV866x5gwyKbbppX3d8PcE9s

$ ppl-token authorize 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o mint 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re
Updating 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
  Current mint authority: 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE
  New mint authority: 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re
Signature: yy7dJiTx1t7jvLPCRX5RQWxNRNtFwvARSfbMJG94QKEiNS4uZcp3GhhjnMgZ1CaWMWe4jVEMy9zQBoUhzomMaxC
```

{% endtab %}

{% tab title="JS" %}

```
const mint = await createMint(
    connection,
    payer,
    multisigKey,
    multisigKey,
    9
  );

const associatedTokenAccount = await getOrCreateAssociatedTokenAccount(
  connection,
  payer,
  mint,
  signer1.publicKey
);
```

{% endtab %}
{% endtabs %}

To demonstrate that the mint account is now under control of the multisig account, attempting to mint with one multisig signer fails

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token mint 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o 1 EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC \
--owner 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re \
--multisig-signer signer-1.json

Minting 1 tokens
  Token: 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
  Recipient: EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC
RPC response error -32002: Transaction simulation failed: Error processing Instruction 0: missing required signature for instruction
```

{% endtab %}

{% tab title="JS" %}

```
try {
  await mintTo(
    connection,
    payer,
    mint,
    associatedTokenAccount.address,
    multisigKey,
    1
  )
} catch (error) {
  console.log(error);
}
// Error: Signature verification failed
```

{% endtab %}
{% endtabs %}

But repeating with a second multisig signer, succeeds

{% tabs %}
{% tab title="CLI" %}

```
$ ppl-token mint 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o 1 EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC \
--owner 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re \
--multisig-signer signer-1.json \
--multisig-signer signer-2.json

Minting 1 tokens
  Token: 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
  Recipient: EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC
Signature: 2ubqWqZb3ooDuc8FLaBkqZwzguhtMgQpgMAHhKsWcUzjy61qtJ7cZ1bfmYktKUfnbMYWTC1S8zdKgU6m4THsgspT
```

{% endtab %}

{% tab title="JS" %}

```
await mintTo(
  connection,
  payer,
  mint,
  associatedTokenAccount.address,
  multisigKey,
  1,
  [
    signer1,
    signer2
  ]
)

const mintInfo = await getMint(
  connection,
  mint
)

console.log(`Minted ${mintInfo.supply} token`);
// Minted 1 token
```

{% endtab %}
{% endtabs %}

### Example: Offline signing with multisig

Sometimes online signing is not possible or desireable. Such is the case for example when signers are not in the same geographic location or when they use air-gapped devices not connected to the network. In this case, we use offline signing which combines the previous examples of multisig with offline signing and a nonce account.

This example will use the same mint account, token account, multisig account, and multisig signer-set keypair filenames as the online example, as well as a nonce account that we create here:

{% tabs %}
{% tab title="CLI" %}

```
$ put-keygen new -o nonce-keypair.json
...
======================================================================
pubkey: Fjyud2VXixk2vCs4DkBpfpsq48d81rbEzh6deKt7WvPj
======================================================================

$ put create-nonce-account nonce-keypair.json 1
Signature: 3DALwrAAmCDxqeb4qXZ44WjpFcwVtgmJKhV4MW5qLJVtWeZ288j6Pzz1F4BmyPpnGLfx2P8MEJXmqPchX5y2Lf3r

$ put nonce-account Fjyud2VXixk2vCs4DkBpfpsq48d81rbEzh6deKt7WvPj
Balance: 0.01 PUT
Minimum Balance Required: 0.00144768 PUT
Nonce blockhash: 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E
Fee: 5000 lamports per signature
Authority: 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE
```

{% endtab %}

{% tab title="JS" %}

```
const connection = new Connection(
  clusterApiUrl('devnet'),
  'confirmed',
);

const onlineAccount = Keypair.generate();
const nonceAccount = Keypair.generate();

const minimumAmount = await connection.getMinimumBalanceForRentExemption(
  NONCE_ACCOUNT_LENGTH,
);

// Form CreateNonceAccount transaction
const transaction = new Transaction()
  .add(
  SystemProgram.createNonceAccount({
    fromPubkey: onlineAccount.publicKey,
    noncePubkey: nonceAccount.publicKey,
    authorizedPubkey: onlineAccount.publicKey,
    lamports: minimumAmount,
  }),
);

await web3.sendAndConfirmTransaction(connection, transaction, [onlineAccount, nonceAccount])

const nonceAccountData = await connection.getNonce(
  nonceAccount.publicKey,
  'confirmed',
);

console.log(nonceAccountData);
/*
NonceAccount {
  authorizedPubkey: '5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE'
  nonce: '6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E',
  feeCalculator: { lamportsPerSignature: 5000 }
}
 */
```

{% endtab %}
{% endtabs %}

For the fee-payer and nonce-authority roles, a local hot wallet at 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE will be used.

{% tabs %}
{% tab title="CLI" %}
First a template command is built by specifying all signers by their public key. Upon running this command, all signers will be listed as "Absent Signers" in the output. This command will be run by each offline signer to generate the corresponding signature.

NOTE: The argument to the --blockhash parameter is the "Nonce blockhash:" field from the designated durable nonce account.

```
$ ppl-token mint 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o 1 EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC \
--owner 46ed77fd4WTN144q62BwjU2B3ogX3Xmmc8PT5Z3Xc2re \
--multisig-signer BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ \
--multisig-signer DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY \
--blockhash 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E \
--fee-payer 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE \
--nonce Fjyud2VXixk2vCs4DkBpfpsq48d81rbEzh6deKt7WvPj \
--nonce-authority 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE \
--sign-only \
--mint-decimals 9
Minting 1 tokens
  Token: 4VNVRJetwapjwYU8jf4qPgaCeD76wyz8DuNj8yMCQ62o
  Recipient: EX8zyi2ZQUuoYtXd4MKmyHYLTjqFdWeuoTHcsTdJcKHC

Blockhash: 6DPt2TfFBG7sR4Hqu16fbMXPj8ddHKkbU4Y3EEEWrC2E
Absent Signers (Pubkey):
 5hbZyJ3KRuFvdy5QBxvE9KwK17hzkAUkQHZTxPbiWffE
 BzWpkuRrwXHq4SSSFHa8FJf6DRQy4TaeoXnkA89vTgHZ
 DhkUfKgfZ8CF6PAGKwdABRL1VqkeNrTSRx8LZfpPFVNY
```

{% endtab %}

{% tab title="JS" %}
First a raw transaction is built using the nonceAccountInformation and tokenAccount key. All signers of the transaction are noted as part of the raw transaction. This transaction will be handed to the signers later for signing.

```
const nonceAccountInfo = await connection.getAccountInfo(
  nonceAccount.publicKey,
  'confirmed'
);

const nonceAccountFromInfo = web3.NonceAccount.fromAccountData(nonceAccountInfo.data);

console.log(nonceAccountFromInfo);

const nonceInstruction = web3.SystemProgram.nonceAdvance({
  authorizedPubkey: onlineAccount.publicKey,
  noncePubkey: nonceAccount.publicKey
});

const nonce = nonceAccountFromInfo.nonce;

const mintToTransaction = new web3.Transaction({
  feePayer: onlineAccount.publicKey,
  nonceInfo: {nonce, nonceInstruction}
})
  .add(
    createMintToInstruction(
      mint,
      associatedTokenAccount.address,
      multisigkey,
      1,
      [
        signer1,
        onlineAccount
      ],
      TOKEN_PROGRAM_ID
    )
  );
  
```

{% endtab %}
{% endtabs %}

Next each offline signer will take the transaction buffer and sign it with their corresponding key.

```
let mintToTransactionBuffer = mintToTransaction.serializeMessage();

let onlineSIgnature = nacl.sign.detached(mintToTransactionBuffer, onlineAccount.secretKey);
mintToTransaction.addSignature(onlineAccount.publicKey, onlineSIgnature);

// Handed to offline signer for signature
let offlineSignature = nacl.sign.detached(mintToTransactionBuffer, signer1.secretKey);
mintToTransaction.addSignature(signer1.publicKey, offlineSignature);

let rawMintToTransaction = mintToTransaction.serialize();
```

Finally, the hot wallet will take the transaction, serialize it, and broadcast it to the network.

```
// Send to online signer for broadcast to network
await web3.sendAndConfirmRawTransaction(connection, rawMintToTransaction);
```

## JSON RPC methods

There is a rich set of JSON RPC methods available for use with PPL Token:

* getTokenAccountBalance
* getTokenAccountsByDelegate
* getTokenAccountsByOwner
* getTokenLargestAccounts
* getTokenSupply

See <https://docs.put.com/apps/jsonrpc-api> for more details.

Additionally the versatile getProgramAccounts JSON RPC method can be employed in various ways to fetch PPL Token accounts of interest.

### Finding all token accounts for a specific mint

To find all token accounts for the TESTpKgj42ya3st2SQTKiANjTBmncQSCqLAZGcPPLGM mint:

```
curl http://api.mainnet-beta.put.com -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getProgramAccounts",
    "params": [
      "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
      {
        "encoding": "jsonParsed",
        "filters": [
          {
            "dataSize": 165
          },
          {
            "memcmp": {
              "offset": 0,
              "bytes": "TESTpKgj42ya3st2SQTKiANjTBmncQSCqLAZGcPPLGM"
            }
          }
        ]
      }
    ]
  }
'
```

The "dataSize": 165 filter selects all Token Accounts, and then the "memcmp": ... filter selects based on the mint address within each token account.

### Finding all token accounts for a wallet

Find all token accounts owned by the vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg user:

```
curl http://api.mainnet-beta.put.com -X POST -H "Content-Type: application/json" -d '
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getProgramAccounts",
    "params": [
      "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
      {
        "encoding": "jsonParsed",
        "filters": [
          {
            "dataSize": 165
          },
          {
            "memcmp": {
              "offset": 32,
              "bytes": "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg"
            }
          }
        ]
      }
    ]
  }
'
```

The "dataSize": 165 filter selects all Token Accounts, and then the "memcmp": ... filter selects based on the owner address within each token account.

## Operational overview

### Creating a new token type

A new token type can be created by initializing a new Mint with the InitializeMint instruction. The Mint is used to create or "mint" new tokens, and these tokens are stored in Accounts.&#x20;

A Mint is associated with each Account, which means that the total supply of a particular token type is equal to the balances of all the associated Accounts.

It's important to note that the InitializeMint instruction does not require the PUT account being initialized also be a signer.&#x20;

The InitializeMint instruction should be atomically processed with the system instruction that creates the PUT account by including both instructions in the same transaction.

Once a Mint is initialized, the mint\_authority can create new tokens using the MintTo instruction.&#x20;

As long as a Mint contains a valid mint\_authority, the Mint is considered to have a non-fixed supply, and the mint\_authority can create new tokens with the MintTo instruction at any time.&#x20;

The SetAuthority instruction can be used to irreversibly set the Mint's authority to None, rendering the Mint's supply fixed.&#x20;

No further tokens can ever be Minted.

Token supply can be reduced at any time by issuing a Burn instruction which removes and discards tokens from an Account.

### Creating accounts&#x20;

Accounts hold token balances and are created using the InitializeAccount instruction.&#x20;

Each Account has an owner who must be present as a signer in some instructions.

An Account's owner may transfer ownership of an account to another using the SetAuthority instruction.

It's important to note that the InitializeAccount instruction does not require the PUT account being initialized also be a signer.&#x20;

The InitializeAccount instruction should be atomically processed with the system instruction that creates the PUT account by including both instructions in the same transaction.

### Transferring tokens&#x20;

Balances can be transferred between Accounts using the Transfer instruction.&#x20;

The owner of the source Account must be present as a signer in the Transfer instruction when the source and destination accounts are different.

It's important to note that when the source and destination of a Transfer are the same, the Transfer will always succeed.&#x20;

Therefore, a successful Transfer does not necessarily imply that the involved Accounts were valid PPL Token accounts, that any tokens were moved, or that the source Account was present as a signer.&#x20;

We strongly recommend that developers are careful about checking that the source and destination are different before invoking a Transfer instruction from within their program.

### Burning&#x20;

The Burn instruction decreases an Account's token balance without transferring to another Account, effectively removing the token from circulation permanently.

There is no other way to reduce supply on chain. This is similar to transferring to an account with unknown private key or destroying a private key.&#x20;

But the act of burning by using Burn instructions is more explicit and can be confirmed on chain by any parties.

### Authority delegation&#x20;

Account owners may delegate authority over some or all of their token balance using the Approve instruction. Delegated authorities may transfer or burn up to the amount they've been delegated.&#x20;

Authority delegation may be revoked by the Account's owner via the Revoke instruction.

### Multisignatures&#x20;

M of N multisignatures are supported and can be used in place of Mint authorities or Account owners or delegates.&#x20;

Multisignature authorities must be initialized with the InitializeMultisig instruction. Initialization specifies the set of N public keys that are valid and the number M of those N that must be present as instruction signers for the authority to be legitimate.

It's important to note that the InitializeMultisig instruction does not require the PUT account being initialized also be a signer.&#x20;

The InitializeMultisig instruction should be atomically processed with the system instruction that creates the PUT account by including both instructions in the same transaction.

### Freezing accounts&#x20;

The Mint may also contain a freeze\_authority which can be used to issue FreezeAccount instructions that will render an Account unusable.&#x20;

Token instructions that include a frozen account will fail until the Account is thawed using the ThawAccount instruction.&#x20;

The SetAuthority instruction can be used to change a Mint's freeze\_authority. If a Mint's freeze\_authority is set to None then account freezing and thawing is permanently disabled and all currently frozen accounts will also stay frozen permanently.

### Wrapping PUT&#x20;

The Token Program can be used to wrap native PUT.&#x20;

Doing so allows native PUT to be treated like any other Token program token type and can be useful when being called from other programs that interact with the Token Program's interface.

Accounts containing wrapped PUT are associated with a specific Mint called the "Native Mint" using the public key So11111111111111111111111111111111111111112.

These accounts have a few unique behaviors

* InitializeAccount sets the balance of the initialized Account to the PUT balance of the PUT account being initialized, resulting in a token balance equal to the PUT balance.
* Transfers to and from not only modify the token balance but also transfer an equal amount of PUT from the source account to the destination account.
* Burning is not supported
* When closing an Account the balance may be non-zero.

The Native Mint supply will always report 0, regardless of how much PUT is currently wrapped.

### Rent-exemption&#x20;

To ensure a reliable calculation of supply, a consistency valid Mint, and consistently valid Multisig accounts all PUT accounts holding an Account, Mint, or Multisig must contain enough PUT to be considered rent exempt

### Closing accounts

An account may be closed using the CloseAccount instruction. When closing an Account, all remaining PUT will be transferred to another PUT account (doesn't have to be associated with the Token Program). Non-native Accounts must have a balance of zero to be closed.

##

## Wallet Integration Guide&#x20;

This section describes how to integrate PPL Token support into an existing wallet supporting native PUT. It assumes a model whereby the user has a single system account as their main wallet address that they send and receive PUT from.

Although all PPL Token accounts do have their own address on-chain, there's no need to surface these additional addresses to the user.

There are two programs that are used by the wallet:

* PPL Token program: generic program that is used by all PPL Tokens
* PPL Associated Token Account program: defines the convention and provides the mechanism for mapping the user's wallet address to the associated token accounts they hold.

### How to fetch and display token holdings&#x20;

The getTokenAccountsByOwner JSON RPC method can be used to fetch all token accounts for a wallet address.

For each token mint, the wallet could have multiple token accounts: the associated token account and/or other ancillary token accounts

By convention it is suggested that wallets roll up the balances from all token accounts of the same token mint into a single balance for the user to shield the user from this complexity.

See the Garbage Collecting Ancillary Token Accounts section for suggestions on how the wallet should clean up ancillary token accounts on the user's behalf.

### Associated Token Account

Before the user can receive tokens, their associated token account must be created on-chain, requiring a small amount of PUT to mark the account as rent-exempt.

There's no restriction on who can create a user's associated token account.&#x20;

It could either be created by the wallet on behalf of the user or funded by a 3rd party through an airdrop campaign.

The creation process is described here.

It's highly recommended that the wallet create the associated token account for a given PPL Token itself before indicating to the user that they are able to receive that PPL Tokens type (typically done by showing the user their receiving address).&#x20;

A wallet that chooses to not perform this step may limit its user's ability to receive PPL Tokens from other wallets.

Sample "Add Token" workflow

The user should first fund their associated token account when they want to receive PPL Tokens of a certain type to:

* Maximize interoperability with other wallet implementations
* Avoid pushing the cost of creating their associated token account on the first sender

The wallet should provide a UI that allow the users to "add a token". The user selects the kind of token, and is presented with information about how much PUT it will cost to add the token.

Upon confirmation, the wallet creates the associated token type as the described here.

Sample "Airdrop campaign" workflow

For each recipient wallet addresses, send a transaction containing:

* Create the associated token account on the recipient's behalf.
* Use TokenInstruction::Transfer to complete the transfer

Associated Token Account Ownership ⚠️ The wallet should never use TokenInstruction::SetAuthority to set the AccountOwner authority of the associated token account to another address.

### Ancillary Token Accounts

At any time ownership of an existing PPL Token account may be assigned to the user. One way to accomplish this is with the ppl-token authorize \<TOKEN\_ADDRESS> owner \<USER\_ADDRESS> command. Wallets should be prepared to gracefully manage token accounts that they themselves did not create for the user.

### Transferring Tokens Between Wallets

The preferred method of transferring tokens between wallets is to transfer into associated token account of the recipient.

The recipient must provide their main wallet address to the sender. The sender then:

* Derives the associated token account for the recipient
* Fetches the recipient's associated token account over RPC and checks that it exists
* If the recipient's associated token account does not yet exist, the sender wallet should create the recipient's associated token account as described here. The sender's wallet may choose to inform the user that as a result of account creation the transfer will require more PUT than normal. However a wallet that chooses to not support creating the recipient's associated token account at this time should present a message to the user with enough information to permit them to find a workaround (such as transferring the token through a fully compliant intermediary wallet such as <https://www.broearn.com/wallet>) to allow the users to accomplish their goal
* Use TokenInstruction::Transfer to complete the transfer

The sender's wallet must not require that the recipient's main wallet address hold a balance before allowing the transfer.

### Registry for token details

At the moment there exist two solutions for Token Mint registries:

hard coded addresses in the wallet or dapp ppl-token-registry package, maintained at <https://github.com/put-labs/token-list> A decentralized solution is in progress.

### Garbage Collecting Ancillary Token Accounts

Wallets should empty ancillary token accounts as quickly as practical by transferring into the user's associated token account. This effort serves two purposes:

* If the user is the close authority for the ancillary account, the wallet can reclaim PUT for the user by closing the account.
* If the ancillary account was funded by a 3rd party, once the account is emptied that 3rd party may close the account and reclaim the PUT.

One natural time to garbage collect ancillary token accounts is when the user next sends tokens. The additional instructions to do so can be added to the existing transaction, and will not require an additional fee.

Cleanup Pseudo Steps:

* For all non-empty ancillary token accounts, add a TokenInstruction::Transfer instruction to the transfer the full token amount to the user's associated token account.
* For all empty ancillary token accounts where the user is the close authority, add a TokenInstruction::CloseAccount instruction

If adding one or more of clean up instructions cause the transaction to exceed the maximum allowed transaction size, remove those extra clean up instructions. They can be cleaned up during the next send operation.

The ppl-token gc command provides an example implementation of this cleanup process.

### Token Vesting

There are currently two solutions available for vesting PPL tokens:

1. Bonfida token-vesting

This program allows you to lock arbitrary PPL tokens and release the locked tokens with a determined unlock schedule. An unlock schedule is made of a unix timestamp and a token amount, when initializing a vesting contract, the creator can pass an array of unlock schedule with an arbitrary size giving the creator of the contract complete control of how the tokens unlock over time.

Unlocking works by pushing a permissionless crank on the contract that moves the tokens to the pre-specified address. The recipient address of a vesting contract can be modified by the owner of the current recipient key, meaning that vesting contract locked tokens can be traded.

* Code: <https://github.com/Bonfida/token-vesting>
* UI: <https://vesting.bonfida.com/#/>
* Audit: The audit was conducted by Kudelski, the report can be found here

1. Streamflow Timelock Enables creation, withdrawal, cancelation and transfer of token vesting contracts using time-based lock and escrow accounts. Contracts are by default cancelable by the creator and transferable by the recipient.

Vesting contract creator chooses various options upon creation, such as:

* PPL token and amount to be vested
* recipient
* exact start and end date
* (optional) cliff date and amount
* (optional) release frequency

Coming soon:

* whether or not a contract is transferable by creator/recipient
* whether or not a contract is cancelable by creator/recipient
* subject/memo

Resources:

* Audit: Reports can be found here and here.
* Application with the UI: <https://app.streamflow.finance/vesting>
* JS SDK: <https://npmjs.com/@streamflow/timelock> (source)
* Rust SDK: <https://crates.io/crates/streamflow-timelock> (source)
* Program code: <https://github.com/streamflow-finance/timelock>

###

###




---

[Next Page](/llms-full.txt/1)

