Security & Audits

Pye's official audit reports and verifications from independent security companies.

Security is engineered into the protocol through a non-custodial architecture that ensures no one can ever take possession of validator identity or withdrawer keys. Instead, the system functions as a transparent wrapper on top of the native Solana Stake Program, where all Principal (PT) and Reward (RT) tokens remain redeemable at maturity effectively acting as a fungible withdraw authorityarrow-up-right.

Security Reviews

Pye programs undergo rigorous 3rd-party audits, ensuring that any security enhancement, no matter how small, is resolved before deployment. Audit reports are organized in the repository according to auditor and date of review.

Auditor
Version
Date
Type
PDF

Zellic

Pye V1

January 23, 2025

Security Review

Sec3

Pye V1

March 19, 2025

Security Review

Neodyme

Pye V2

June 5, 2025

Security Review

Sec3

Pye V2

November 2025

Security Review

Neodyme

Pye V2 (revised)

November 2025

Security Review

Validator Security & Ops FAQ

chevron-rightWhen we set commissions are the % calculated from the current on-chain commissions or is it an absolute value (meaning if I put 100% on inflation here it will overwrite our current 7% commission and delegator gets nothing?)hashtag

They are absolute, meaning they overwrite public commissions.

The commissions set in the form are the percentages the validator keeps. Setting inflation to 100% will effectively give stakers 0% inflation.

chevron-rightWhen I create a lockup can I use any SOL wallet or do I need to whitelist it first?hashtag

  • Public lockup: any SOL from any wallet

  • Single Depositor lockup: only SOL from the specified wallet

chevron-rightIf an Issuer Key is compromised, what is the process to revoke it and assign a new one without affecting active lockups?hashtag

There is no way to truly rotate the issuer keys because the on-chain Lockup account is immutable (in the current iteration of the program).

If an issuer key is compromised, an adversary could create Lockups with 100% of inflation, MEV, and block rewards going to stakers.

Mitigations:

  • CLI v1 (v0.1.3):

    • If running validator-pye-account-manager and the compromised issuer key is still enabled, the CLI will honor all matching Lockups.

    • Mitigation option 1: Do not run validator-pye-account-manager and instead manually run transfer-excess-rewards for each Lockup each epoch.

    • Mitigation option 2: Patch CLI v1 to accept a list of Lockup pubkeys, removing reliance on issuer keys (higher operational burden).

  • CLI v2 (WIP):

    • Issuer keys could be removed entirely.

    • Associations between Organizations and Lockups would rely on Pye backend user authentication instead of on-chain issuer keys.

chevron-rightIs it possible to rotate the Issuer Key associated with a lockup or validator organization?hashtag

The issuer keys stored under an Organization in the Pye database can be changed at any time by a user with the role Admin or Member (effectively rotating keys).

The on-chain Lockup stores the issuer key as the key that originally created the Lockup. It was added to the on-chain account data as a simple way for the v1 CLI to be able to filter Lockups and mitigate a scenario where the v1 CLI would subscribe to honoring all lockups purely based on vote key. The Lockup account data is immutable and cannot be changed. Thus the issuer key stored on-chain cannot be changed.

In v1 of the CLI, the issuer keys are passed directly into the CLI by the operator. This is because the v1 CLI was intended to be open sourced operational software that did not have any ties to the Pye DB and backend. A more decentralized approach.

The [yet to be released] v2 CLI will be using these issuer keys stored under an Organization in the Pye DB as a way to filter Lockups. This is very similar to how the v1 CLI worked, only that the issuer keys are being pulled directly from the database.

chevron-rightCan a user with the "Member" role generate and rotate Issuer Keys, or is that action restricted strictly to "Admins".hashtag

Both Admins and Members can manage issuer keys and invite users.

  • Admin: manage roles, issuer keys, invite

  • Member: manage issuer keys (only for self), invite

chevron-rightFor CLI users, are there any other consequence if the node is down outside epoch changes?hashtag

Yes. CLI v1 depends on the RPC node and Jito’s API. It requires knowing the active stake for the previous epoch to calculate rewards correctly.

There is no way to determine active stake for current_epoch - 2. This means missing epochs can result in unrecoverable reward calculation gaps.

There is a separate CLI command that allows calculating rewards for current_epoch - 1. If the CLI is started with the long-running manager command, you would want to use the transfer command and then restart the manager to wait for the next boundary.

chevron-rightFor CLI users, how many epochs should avoid being missed? What happens to rewards for missed epochs?hashtag

You should avoid missing any epoch. If you miss an epoch and were supposed to pay lamports to a Lockup, the UI will highlight this error.

Currently there is no harsh protocol penalty — mostly social consequences. However, there has been exploration into allowing stakers to early-withdraw if payments are missed for a certain number of epochs.

Because stakers are locked up, you can make good on the payment in epoch + 2 (as long as it’s before maturity). Stakers are still rewarded, but they may miss out on compounding for the missed epoch.

chevron-rightFor CLI users, does the CLI need to be online at the exact moment of the epoch boundary? What happens if we need to reboot the server for maintenance.hashtag

There are two commands in CLI v1 (v0.1.3):

  • validator-pye-account-manager

    • Long-running process

    • Waits for the next epoch boundary

    • If started late, it does not backfill missed epochs

  • transfer-excess-rewards

    • One-shot command

    • If run in epoch N, it calculates rewards for epoch N-1 and executes the transfer

Safe timing considerations:

  • Avoid rebooting in the first ~12 hours after an epoch boundary

  • MEV data (e.g., from Jito) can take hours to populate

  • The middle of the epoch is safest

The lockup Payment Tracker uses checkpoint-based recovery, so no data is missed after restarts.

Practical recommendation: Schedule maintenance mid-epoch (≈ 1–1.5 days after epoch start).

chevron-rightFor CLI users, does the CLI Hot Wallet (used for distributing rewards) need to be whitelisted/registered on-chain, or is it simply a funding source for gas/transactions? If it's just a funding source, can we rotate this wallet periodically without protocol interaction?hashtag

Yes — it is purely a funding source and can be rotated periodically without protocol interaction. This operation is done off-chain.

chevron-rightFor CLI users, is it tied to an IP or can we run it again on a new server if it goes down for any reason?hashtag

CLI v1 was built without dependencies on Pye’s backend.

There are no IP restrictions other than:

  • The RPC node being used

  • Jito’s MEV API (currently no IP restrictions)

There is ongoing exploration into using durable nonces to mitigate double-spend risks if multiple instances are run simultaneously.

chevron-rightFor CLI users of CLI V1, will migrating to CLI V2 break the V1 integration?hashtag

No, it won’t break it. It’s a completely separate code base and you can continue to use V1 if you so choose.

If you choose to migrate to V2, you will need to schedule a maintenance window in-between epochs to spin down V1 and spin up V2. At the next epoch boundary V2 will make the 1st payment.

Migration to V2 is straightforward, any node operator should have no issues running the commands to spin V2 up. From a state transition perspective, the important thing to understand is that V1 CLI is is winded down during this maintenance window and that the V2 CLI is spun up and will fund the next epoch payments.

chevron-rightFor CLI users, how heavy are the RPC request costs?hashtag

It is efficiently written to reduce RPC calls. The two areas where it uses a decent amount of RPC calls is getting the block metadata where your validator was the leader and polling for the epoch boundary. The concurrency of get_block calls can be limited by the —currency CLI argument. The epoch polling frequency can be adjusted via the —cycle-secs CLI argument.

For a single iteration (one epoch):

Total RPC Calls ≈

I # get_program_accounts (per issuer)

  • (0 or 1) # get_multiple_accounts (if allow_post_maturity)

  • (slots_remaining / cycle_secs) # get_epoch_info during wait

  • 4 # get_block_time, get_vote_accounts, get_leader_schedule, get_account(SlotHistory)

  • B # get_block (based on validator's blocks in epoch)

  • P * (3 to 6) # per pye_account stake fetching

  • P * (1 to 2) # per pye_account inflation reward

  • T * 2 # transfers (T = accounts with excess rewards, if not dry_run)

Typical Example for a validator with:

  • 1 issuer

  • 500 blocks produced in the epoch

  • 5 active pye accounts (no transient accounts)

  • Not dry_run, all 5 have excess rewards

≈ 1 + 100 + 4 + 500 + (5 * 3) + (5 * 1) + (5 * 2)

≈ 1 + 100 + 4 + 500 + 15 + 5 + 10

≈ 635 RPC calls per iteration

circle-info

For any other security-related inquiries, reach out to our team:

Email: [email protected]envelope

Last updated