Skip to content

[nodes] has_one account resolution #605

Open

Description

@ChewingGlass

Let's say you have an endpoint like this:

#[derive(Accounts)]
pub struct DequeuetaskV0<'info> {
    pub queue_authority: Signer<'info>,
    /// CHECK: Via has one
    #[account(mut)]
    pub rent_refund: AccountInfo<'info>,
    #[account(
        seeds = [b"task_queue_authority", task_queue.key().as_ref(), queue_authority.key().as_ref()],
        bump = task_queue_authority.bump_seed,
    )]
    pub task_queue_authority: Box<Account<'info, TaskQueueAuthorityV0>>,
    #[account(mut)]
    pub task_queue: Box<Account<'info, TaskQueueV0>>,
    #[account(
        mut,
        close = rent_refund,
        has_one = rent_refund,
        has_one = task_queue,
    )]
    pub task: Box<Account<'info, TaskV0>>,
}

In Anchor, the code to use this endpoint is:

await program.methods
          .dequeueTaskV0()
          .accounts({
            task,
          })
          .rpc();

In Codama, the code is:

 const task = ... // fetch task account
await dequeueTaskV0(umi, {
  task,
  queueAuthority,
  rentRefund: task.rentRefund,
  taskQueue: task.taskQueue 
}).sendAndConfirm(umi, options);

For more complex endpoints with 10+ accounts, and lots of has_ones, you end up with heaps of boilerplate just to get what needs to be passed to the function.

It would be nice if Codama could use anchor's has_one information from the IDL to make accounts optional in typescript. If you pass them, you avoid an extra fetch. If you don't, it fetches them for you.

So, for example, the code becomes:

await dequeueTaskV0(umi, { task }).sendAndConfirm(umi, options);

Another optimization on top of this would be to implement a global cache of accounts, similar to Helium's Account Fetch Cache that makes it so you can omit passing optional accounts for more legible code, without the worry about a performance hit.

This feature also becomes useful if you need to add accounts to an endpoint without breaking old clients. If the clients are smart enough to resolve has_one's, a new account pulled in through has_one is a non-breaking change.

Activity

  1. changed the title [-]Feature Request: has_one account resolution[/-] [+]has_one account resolution[/+] on Sep 12, 2025
  2. changed the title [-]has_one account resolution[/-] [+][nodes] has_one account resolution[/+] on Sep 12, 2025
  3. added
    v2Something to look into when updating the Codama standard to v2
    proposalSuggesting a change / new feature
    on Sep 12, 2025
  4. lorisleiva commented on Sep 12, 2025

    @lorisleiva
    Member

    Thank you for writing up this issue btw.

    As you know I'm not a fan of forcing users to magically fetch various accounts just to create a single instruction when the accounts are likely already loaded on the app. That being said, I do want that information to exist on the IDL because it is a valuable piece of information that can be used by any visitor. Perhaps an opt-in option on a renderer somewhere could even materialise this auto-fetching of account strategy.

    I've just remember that I wrote an issue a while ago about adding the concept of "Constraints" to certain nodes like AccountNodes or InstructionAccountNodes. As you can see, I even mention the has_one constraint on the issue. Perhaps this would be a good way to include this information on the standard and it would be up to the renderer to decide whether to use this constraint as a default value if none exist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    anchorImproves conversion from Anchor IDLproposalSuggesting a change / new featurev2Something to look into when updating the Codama standard to v2

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions