diff --git a/CHANGELOG.md b/CHANGELOG.md
index f0b8e67125..88398ea459 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,10 @@ incremented for features.
## [Unreleased]
+### Features
+
+* lang: Add `seeds::program` constraint for specifying which program_id to use when deriving PDAs.([#1197](https://github.com/project-serum/anchor/pull/1197))
+
### Breaking
* lang: rename `loader_account` module to `account_loader` module ([#1279](https://github.com/project-serum/anchor/pull/1279))
diff --git a/examples/tutorial/yarn.lock b/examples/tutorial/yarn.lock
index e47e8a3522..b199202596 100644
--- a/examples/tutorial/yarn.lock
+++ b/examples/tutorial/yarn.lock
@@ -30,10 +30,10 @@
"@ethersproject/logger" "^5.5.0"
hash.js "1.1.7"
-"@project-serum/anchor@^0.19.0":
- version "0.19.0"
- resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.19.0.tgz#79f1fbe7c3134860ccbfe458a0e09daf79644885"
- integrity sha512-cs0LBmJOrL9eJ8MRNqitnzbpCT5QEzVdJmiIjfNV5YaGn1K9vISR7DtISj3Bdl3KBdLqii4CTw1mpHdi8iXUCg==
+"@project-serum/anchor@^0.20.0":
+ version "0.20.0"
+ resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.20.0.tgz#547f5c0ff7e66809fa7118b2e3abd8087b5ec519"
+ integrity sha512-p1KOiqGBIbNsopMrSVoPwgxR1iPffsdjMNCOysahTPL9whX2CLX9HQCdopHjYaGl7+SdHRuXml6Wahk/wUmC8g==
dependencies:
"@project-serum/borsh" "^0.2.2"
"@solana/web3.js" "^1.17.0"
diff --git a/lang/derive/accounts/src/lib.rs b/lang/derive/accounts/src/lib.rs
index 902dfd6ecd..d09778d385 100644
--- a/lang/derive/accounts/src/lib.rs
+++ b/lang/derive/accounts/src/lib.rs
@@ -159,7 +159,9 @@ use syn::parse_macro_input;
/// you can pass it in as instruction data and set the bump value like shown in the example,
/// using the instruction_data
attribute.
/// Anchor will then check that the bump returned by find_program_address
equals
-/// the bump in the instruction data.
+/// the bump in the instruction data.
+/// seeds::program
cannot be used together with init because the creation of an
+/// account requires its signature which for PDAs only the currently executing program can provide.
///
///
/// Example:
@@ -228,21 +230,42 @@ use syn::parse_macro_input;
///
#[account(seeds = <seeds>, bump)]
#[account(seeds = <seeds>, bump = <expr>)]
+/// #[account(seeds = <seeds>, bump, seeds::program = <expr>)]
+/// #[account(seeds = <seeds>, bump = <expr>)]
+/// #[account(seeds = <seeds>, bump = <expr>, seeds::program = <expr>)]
///
seeds::program = <expr>
to derive the PDA from a different
+/// program than the currently executing one.init
.
/// See its description.
///
-/// #[account(seeds = [b"example_seed], bump)]
-/// pub canonical_pda: AccountInfo<'info>,
-/// #[account(seeds = [b"other_seed], bump = 142)]
-/// pub arbitrary_pda: AccountInfo<'info>
+/// #[derive(Accounts)]
+/// #[instruction(first_bump: u8, second_bump: u8)]
+/// pub struct Example {
+/// #[account(seeds = [b"example_seed], bump)]
+/// pub canonical_pda: AccountInfo<'info>,
+/// #[account(
+/// seeds = [b"example_seed],
+/// bump,
+/// seeds::program = other_program.key()
+/// )]
+/// pub canonical_pda_two: AccountInfo<'info>,
+/// #[account(seeds = [b"other_seed], bump = first_bump)]
+/// pub arbitrary_pda: AccountInfo<'info>
+/// #[account(
+/// seeds = [b"other_seed],
+/// bump = second_bump,
+/// seeds::program = other_program.key()
+/// )]
+/// pub arbitrary_pda_two: AccountInfo<'info>,
+/// pub other_program: Program<'info, OtherProgram>
+/// }
///
///