davidtranhq / solana-whitelist

A Solana program (smart contract) providing basic whitelisting functionality.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Solana Whitelisting

This Solana program (smart contract) provides basic whitelisting functionality using PDAs. It was written using Anchor.

The program is deployed on Solana's Devnet at 7Q5v4ftKm5Xk88NMf5kNCkvLmmBPcBfkynJA9x244i5Q. It is not yet deployed on Mainnet.

IDL files and TypeScript type files can be found in target/.

Build

  1. Install Anchor.
  2. Navigate to the project root and run anchor build. This compiles the project and generates a keypair for the program based on your personal wallet.
  3. The following steps only need to be performed on the first build (to replace the public key with one corresponding to your personal wallet).
    1. Run anchor keys list to get the new public key for the program.
    2. Replace all occurences of the old public key in the project (7Q5v4ftK...) with the new public key.
    3. Re-compile with anchor build (to account for the replacement of the public key in the source code).
  4. Run anchor deploy to deploy the compiled program on the blockchain.
  5. Run the tests with anchor run test.

Endpoints

init_whitelist(name: String) -> Result<()>

Arguments:

  • name: String The identifying name of this whitelist. Since whitelists are tied to the signer's wallet, the name need be unique to other whitelists initialized by the signer.

Accounts:

  • whitelist The whitelist to be initialized. The address should be a PDA derived from this whitelisting program address and seeded with the signer's public key and the whitelist name (as bytes). Uses the canonical bump.
  • authority The signer of this transaction. This account will pay for the whitelist and new whitelist entries. Only this account is able to add to the whitelist.
delete_whitelist(name: String) -> Result<()>

Note that deleting a whitelist does not delete the whitelist entries associated with it. Use remove_from_whitelist to delete whitelist entries.

Arguments:

  • name: String The name of the whitelist to delete.

Accounts:

  • whitelist The whitelist to delete. This account will be closed and remaining lamports will be sent to authority.
  • authority The signer of this transaction. This account must be the one that created the whitelist.
add_to_whitelist(account_to_whitelist: Pubkey) -> Result<()>

Arguments:

  • account_to_whitelist: Pubkey The address of the account to add to the whitelist.

Accounts:

  • entry The account to store the new whitelist entry. The address should be a PDA derived from this whitelisting program address and seeded with account_to_add and the public key of whitelist. Uses the canonical bump.
  • whitelist The whitelist to add to, initialized with init_whitelist. authority must be the one who initialized this whitelist.
  • authority The signer of this transaction. This must correspond to the account that initialized the whitelist.
delete_from_whitelist(account_to_delete: Pubkey) -> Result<()>

Arguments:

  • account_to_delete: Pubkey The address of the account to remove from the whitelist.

Accounts:

  • entry The whitelist entry (initialized with add_to_whitelist) corresponding with account_to_delete.
  • whitelist The whitelist to remove from (initialized with init_whitelist). authority must be the one who initialized this whitelist.
  • authority The signer of this transaction. This must correspond to the account that initialized the whitelist.
check_whitelisted(account_to_check: Pubkey) -> Result<()>

Throws an AnchorError if the user is not whitelisted. Unlike other endpoints, this endpoint can be called even by those who did not create the whitelist.

Arguments:

  • account_to_check The public key of the account whose whitelisting status will be checked.

Accounts:

  • entry The whitelisting entry of account_to_check (initialized with add_to_whitelist).
  • whitelist The whitelist that will be checked.

Usage

Creating a whitelist

First, create a PDA for an account that will hold a named whitelist. The PDA should be derived from the address of this whitelisting program and seeded with your wallet public key and the whitelist name (in bytes), in that order.

The whitelist name is used as an identifier to differentiate between the whitelists already associated with your wallet. As such, the name should be different from any of your existing whitelists created with this program.

import * as anchor from "@project-serum/anchor";

const whitelistName = "Whitelist Name";

const [whitelist, whitelistBump] = await anchor.web3.PublicKey.findProgramAddress(
    [
        wallet.publicKey.toBytes(),
        anchor.utils.bytes.utf8.encode(whitelistName)
    ],
    whitelistProgram.programId // the address of this whitelisting program
);

Then, initialize the whitelist with a call to init_whitelist:

const systemProgram = anchor.web3.SystemProgram;

await whitelistProgram.methods
    .initWhitelist(whitelistName)
    .accounts({
        whitelist,
        authority: wallet.publicKey,
        systemProgram: systemProgram.programId,
    })
    .rpc();

The funds used to create the account are taken from authority.

Adding accounts to the whitelist

First, create a PDA for the account that will hold the whitelist entry for one address. The PDA should be derived from the address of this whitelisting program and seeded with the address of the whitelist (see Creating a whitelist) and the account to whitelist.

Note that the authority of the transaction sending the instruction add_to_whitelist must be the same as the one who created the whitelist.

const accountToWhitelist: Pubkey = "SomePublicKey";

const [whitelistEntry, entryBump] = await anchor.web3.PublicKey.findProgramAddress(
    [
        accountToWhitelist.toBytes(),
        whitelist.toBytes(),
    ],
    program.programId // ID of this whitelisting program
);

Then, add the account to the whitelist with a call to add_to_whitelist:

await program.methods
    .addToWhitelist(accountToWhitelist.publicKey)
    .accounts({
        entry: whitelistEntry,
        whitelist: whitelist,
        authority: wallet.publicKey,
        systemProgram: systemProgram.programId,
    })
    .rpc();

Checking if an account is whitelisted

Use the check_whitelisted endpoint: check_whitelisted throws if the user is not whitelisted.

try {
    await program.methods
        .checkWhitelisted(accountToWhitelist.publicKey)
        .accounts({
            entry: whitelistEntry,
            whitelist: whitelist,
        })
        .rpc();
    // user is whitelisted
} catch (err: unknown) {
    // user is not whitelisted
}

Deleting an account from the whitelist

Use the delete_from_whitelist endpoint. Only the creator of the whitelist can remove from the whitelist. The remaining lamports stored in the whitelist entry account are returned to the authority (creator of the whitelist).

await program.methods
    .deleteFromWhitelist(accountToWhitelist.publicKey)
    .accounts({
        entry: whitelistEntry,
        whitelist: whitelist,
        authority: wallet.publicKey,
    })
    .rpc()

Deleting a whitelist

Use the delete_whitelist endpoint. Only the creator of the whitelist can delete the whitelist. The remaining lamports stored in the whitelist entry account are returned to the authority (creator of the whitelist).

This endpoint does NOT remove corresponding whitelist entries; they have to be removed separately with remove_from_whitelist.

await program.methods
    .deleteWhitelist(whitelistName)
    .accounts({
    whitelist,
    authority: wallet.publicKey,
    })
    .rpc();

About

A Solana program (smart contract) providing basic whitelisting functionality.


Languages

Language:Rust 100.0%