Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storage subset merkle tree onchain #21

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

docongminh
Copy link

@docongminh docongminh commented Jan 22, 2025

Flow for storage a part of proof onchain:

  1. Operator create a distributor root
  2. Operator create distributors
  3. Operator create canopy tree for each distributor.
  4. Admin fund to distributor root
  5. Permissionless: fund distributor from distributor root.

Note:
I quickly tested the NewClaimAndStake transaction locally using:

  • depth: 2
  • proof length: 2

The resulting transaction size was 661 bytes. That means we have about 571 bytes of remaining space, which should accommodate roughly 17 proofs for this transaction in this case.

@docongminh docongminh changed the title [draft] Add partial merkle tree Storage subset merkle tree onchain Jan 23, 2025
pub struct DistributeVault<'info> {
/// The [ParentState].
#[account(has_one = admin)]
pub parent_account: AccountLoader<'info, ParentAccount>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DisitributorRoot

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated


/// Accounts required for distributing tokens from the parent vault to distributor vaults.
#[derive(Accounts)]
pub struct DistributeVault<'info> {
Copy link

@andrewsource147 andrewsource147 Feb 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FundMerkleDisitributorFromRoot

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

#[derive(Accounts)]
pub struct DistributeVault<'info> {
/// The [ParentState].
#[account(has_one = admin)]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

permissionless?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

pub parent_vault: Account<'info, TokenAccount>,

/// Admin
pub admin: Signer<'info>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need admin here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

// [distributor_vault, distributor, distributor_vault, distributor]
let remaining_accounts: &[AccountInfo] = ctx.remaining_accounts;
// Ensure valid layout.
if remaining_accounts.len() % 2 != 0 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need remaninings accounts here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

);

// Check distributor has been funded token
if distributor_vault.amount >= distributor_state.max_total_claim {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

distributor_state.funded_amount

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

pub struct NewDistributorParams {
pub version: u64,
pub root: [u8; 32],
pub total_nodes: u8,
pub depth: u8,
pub nodes: Vec<[u8; 32]>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

push in last account

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

pub struct NewDistributorParams {
pub version: u64,
pub root: [u8; 32],
pub total_nodes: u8,
pub depth: u8,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you test max depth

@@ -127,6 +132,19 @@ pub struct NewDistributor<'info> {
)]
pub distributor: AccountLoader<'info, MerkleDistributor>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use init_if_needed for token_vault

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

payer = admin
)]
pub partial_merkle_tree: Account<'info, PartialMerkleTree>,

/// Base key of the distributor.
pub base: Signer<'info>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use admin as unchecked_account, and payer to pay for rent

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

space = PartialMerkleTree::space(total_node as usize),
payer = admin
)]
pub partial_merkle_tree: Account<'info, PartialMerkleTree>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

save nodes in distributor state

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because AccountLoader does not support storing a dynamic Vec directly. So, create CanopyTree to storage metadata (root, nodes, depth..) of MerkleDistributor

@@ -30,6 +34,7 @@ pub struct NewDistributorParams {
pub claim_type: u8,
pub operator: Pubkey,
pub locker: Pubkey,
pub parent_account: Pubkey,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parent should be pda of base + mint

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

init,
seeds = [
b"ParentAccount".as_ref(),
mint.key().to_bytes().as_ref(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pda of mint and base

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto^

/// Parent vault
/// Should create previously
#[account(
associated_token::mint = mint,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init if need

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

pub system_program: Program<'info, System>,
}

pub fn handle_new_parent_account(ctx: Context<NewParentAccount>) -> Result<()> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

max amount claim and max node

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

use anchor_spl::token::{Mint, TokenAccount};

#[derive(Accounts)]
pub struct NewParentAccount<'info> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a function to transfer fund to parent account

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done with FundDistributorRoot

let mut parent_account = ctx.accounts.parent_account.load_init()?;

parent_account.bump = *ctx.bumps.get("parent_account").unwrap();
parent_account.admin = ctx.accounts.admin.key();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we dont need parent account

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

partial_merkle_tree.depth,
initial_index,
proof,
partial_merkle_tree.nodes.clone(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should use &partial_merkle_tree.nodes.clone()

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

/// Token Address of parent vault
pub parent_vault: Pubkey,
/// Padding
pub padding: u64,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need padding here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants