Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- idl: Add `IdlBuilder` ([#3188](https://github.com/coral-xyz/anchor/pull/3188)).
- cli: Make `clean` command also remove the `.anchor` directory ([#3192](https://github.com/coral-xyz/anchor/pull/3192)).
- lang: Deprecate `#[interface]` attribute ([#3195](https://github.com/coral-xyz/anchor/pull/3195)).
- ts: Include unresolved accounts in the resolution error message ([#3207](https://github.com/coral-xyz/anchor/pull/3207)).

### Fixes

Expand Down
13 changes: 13 additions & 0 deletions tests/pda-derivation/programs/pda-derivation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ pub mod pda_derivation {
pub fn seed_math_expr(_ctx: Context<SeedMathExpr>) -> Result<()> {
Ok(())
}

pub fn resolution_error(_ctx: Context<ResolutionError>) -> Result<()> {
Ok(())
}
}

#[derive(Accounts)]
Expand Down Expand Up @@ -178,6 +182,15 @@ pub struct SeedMathExpr<'info> {
pub math_expr_account: UncheckedAccount<'info>,
}

#[derive(Accounts)]
pub struct ResolutionError<'info> {
pub unknown: UncheckedAccount<'info>,
#[account(seeds = [unknown.key.as_ref()], bump)]
pub pda: UncheckedAccount<'info>,
#[account(seeds = [pda.key.as_ref()], bump)]
pub another_pda: UncheckedAccount<'info>,
}

#[account]
pub struct MyAccount {
data: u64,
Expand Down
13 changes: 13 additions & 0 deletions tests/pda-derivation/tests/typescript.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,17 @@ describe("typescript", () => {
it("Can use unsupported expressions", () => {
// Compilation test to fix issues like https://github.com/coral-xyz/anchor/issues/2933
});

it("Includes the unresolved accounts if resolution fails", async () => {
try {
// `unknown` account is required for account resolution to work, but it's
// intentionally not provided to test the error message
await program.methods.resolutionError().rpc();
throw new Error("Should throw due to account resolution failure!");
} catch (e) {
expect(e.message).to.equal(
"Reached maximum depth for account resolution. Unresolved accounts: `pda`, `anotherPda`"
);
}
});
});
38 changes: 37 additions & 1 deletion ts/packages/anchor/src/program/accounts-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,43 @@ export class AccountsResolver<IDL extends Idl> {
) {
depth++;
if (depth === 16) {
throw new Error("Reached maximum depth for account resolution");
const isResolvable = (acc: IdlInstructionAccountItem) => {
if (!isCompositeAccounts(acc)) {
return !!(acc.address || acc.pda || acc.relations);
}

return acc.accounts.some(isResolvable);
};

const getPaths = (
accs: IdlInstructionAccountItem[],
path: string[] = [],
paths: string[][] = []
) => {
for (const acc of accs) {
if (isCompositeAccounts(acc)) {
paths.push(...getPaths(acc.accounts, [...path, acc.name]));
} else {
paths.push([...path, acc.name]);
}
}

return paths;
};

const resolvableAccs = this._idlIx.accounts.filter(isResolvable);
const unresolvedAccs = getPaths(resolvableAccs)
.filter((path) => !this.get(path))
.map((path) => path.reduce((acc, p) => acc + "." + p))
.map((acc) => `\`${acc}\``)
.join(", ");

throw new Error(
[
`Reached maximum depth for account resolution.`,
`Unresolved accounts: ${unresolvedAccs}`,
].join(" ")
);
}
}
}
Expand Down