Skip to content

Commit

Permalink
idl: Fix using address constraint with non-const expressions (#3216)
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto authored Aug 31, 2024
1 parent 1e3c15e commit 467ae43
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- idl: Fix panicking on tests ([#3197](https://github.com/coral-xyz/anchor/pull/3197)).
- lang: Remove `arrayref` dependency ([#3201](https://github.com/coral-xyz/anchor/pull/3201)).
- cli: Fix template code shouldn't escape ([#3210](https://github.com/coral-xyz/anchor/pull/3210)).
- idl: Fix using `address` constraint with non-const expressions ([#3216](https://github.com/coral-xyz/anchor/pull/3216)).

### Breaking

Expand Down
20 changes: 19 additions & 1 deletion lang/syn/src/idl/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,25 @@ fn get_address(acc: &Field) -> TokenStream {
.address
.as_ref()
.map(|constraint| &constraint.address)
.filter(|address| !matches!(address, syn::Expr::Field(_)))
.filter(|address| {
match address {
// Allow constants (assume the identifier follows the Rust naming convention)
// e.g. `crate::ID`
syn::Expr::Path(expr) => expr
.path
.segments
.last()
.unwrap()
.ident
.to_string()
.chars()
.all(|c| c.is_uppercase() || c == '_'),
// Allow `const fn`s (assume any stand-alone function call without an argument)
// e.g. `crate::id()`
syn::Expr::Call(expr) => expr.args.is_empty(),
_ => false,
}
})
.map(|address| quote! { Some(#address.to_string()) })
.unwrap_or_else(|| quote! { None }),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub mod relations_derivation {
Ok(())
}

pub fn test_address_relation(_ctx: Context<TestAddressRelation>) -> Result<()> {
pub fn test_address(_ctx: Context<TestAddress>) -> Result<()> {
Ok(())
}
}
Expand Down Expand Up @@ -66,9 +66,20 @@ pub struct TestRelation<'info> {
}

#[derive(Accounts)]
pub struct TestAddressRelation<'info> {
pub struct TestAddress<'info> {
// Included wit the `address` field in IDL
// It's actually `static` but it doesn't matter for our purposes
#[account(address = crate::ID)]
constant: UncheckedAccount<'info>,
#[account(address = crate::id())]
const_fn: UncheckedAccount<'info>,

// Not included with the `address` field in IDL
#[account(address = my_account.my_account)]
account: UncheckedAccount<'info>,
field: UncheckedAccount<'info>,
#[account(address = my_account.my_account())]
method: UncheckedAccount<'info>,

#[account(seeds = [b"seed"], bump = my_account.bump)]
my_account: Account<'info, MyAccount>,
}
Expand All @@ -78,3 +89,9 @@ pub struct MyAccount {
pub my_account: Pubkey,
pub bump: u8,
}

impl MyAccount {
pub fn my_account(&self) -> Pubkey {
self.my_account
}
}
11 changes: 8 additions & 3 deletions tests/relations-derivation/tests/typescript.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,13 @@ describe("typescript", () => {
await tx.rpc();
});

it("Can use relations derivation with `address` constraint", () => {
// Only compile test for now since the IDL spec doesn't currently support field access
// expressions for the `address` constraint
it("Can use `address` constraint", () => {
const ix = program.idl.instructions.find(
(ix) => ix.name === "testAddress"
)!;
expect(ix.accounts.find((acc) => acc.name === "constant")!.address).to.not
.be.undefined;
expect(ix.accounts.find((acc) => acc.name === "constFn")!.address).to.not.be
.undefined;
});
});

0 comments on commit 467ae43

Please sign in to comment.