Skip to content

Commit 6e29738

Browse files
Adding execute delegation capabilities (#262)
* Adding agent identity external plugin * Fix AI feedback * Fixig wrong flag and adding more tests * Fixing init collection with plugin * Fixing coderabbit comments * Identity plugin should only be addable by ID program * Switching to mollusk tests to pass * Bump versions * Feedback * Adding execute delegation capabilities * Pointing to crates --------- Co-authored-by: Sarah Strange <16522636+stranzhay@users.noreply.github.com>
1 parent 0078f56 commit 6e29738

5 files changed

Lines changed: 1199 additions & 11 deletions

File tree

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

programs/mpl-core/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ mpl-utils = "0.4.1"
2323
spl-noop = { version = "1.0.0", features = ["cpi"] }
2424
podded = "0.5.1"
2525
strum = { version = "0.26.1", features = ["derive"] }
26-
mpl-agent-identity = "0.1.0"
27-
mpl-agent-tools = "0.1.0"
26+
mpl-agent-identity = "0.2.0"
27+
mpl-agent-tools = "0.2.0"
2828

2929
[dev-dependencies]
3030
mollusk-svm = "0.5.0"

programs/mpl-core/src/plugins/external/agent_identity.rs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use borsh::{BorshDeserialize, BorshSerialize};
2+
use mpl_agent_tools::accounts::ExecutionDelegateRecordV1;
23
use mpl_utils::{assert_derivation, assert_signer};
34
use solana_program::{
45
account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
@@ -8,8 +9,8 @@ use solana_program::{
89
use crate::{
910
error::MplCoreError,
1011
plugins::{
11-
abstain, reject, Authority, ExternalCheckResult, HookableLifecycleEvent, PluginValidation,
12-
PluginValidationContext, ValidationResult,
12+
abstain, approve, reject, Authority, ExternalCheckResult, HookableLifecycleEvent,
13+
PluginValidation, PluginValidationContext, ValidationResult,
1314
},
1415
};
1516

@@ -45,6 +46,30 @@ impl AgentIdentity {
4546

4647
Ok(())
4748
}
49+
50+
/// Verify that the Execution Delegate is valid for the asset.
51+
pub fn verify_execution_delegate(
52+
asset: &Pubkey,
53+
authority: &Pubkey,
54+
maybe_execution_delegate_record: &AccountInfo,
55+
) -> Result<ValidationResult, ProgramError> {
56+
// If the account there is owned by the mpl-agent-tools program, then it's probably an execution delegate record.
57+
if maybe_execution_delegate_record.owner == &mpl_agent_tools::ID
58+
&& maybe_execution_delegate_record.data_len() > 0
59+
&& maybe_execution_delegate_record.data.borrow()[0]
60+
== mpl_agent_tools::types::Key::ExecutionDelegateRecordV1 as u8
61+
{
62+
let execution_delegate_record =
63+
ExecutionDelegateRecordV1::try_from(maybe_execution_delegate_record)?;
64+
if execution_delegate_record.agent_asset == *asset
65+
&& execution_delegate_record.authority == *authority
66+
{
67+
return approve!();
68+
}
69+
}
70+
71+
abstain!()
72+
}
4873
}
4974

5075
impl PluginValidation for AgentIdentity {
@@ -101,9 +126,17 @@ impl PluginValidation for AgentIdentity {
101126

102127
fn validate_execute(
103128
&self,
104-
_ctx: &PluginValidationContext,
129+
ctx: &PluginValidationContext,
105130
) -> Result<ValidationResult, ProgramError> {
106-
abstain!()
131+
if ctx.asset_info.is_some() && ctx.accounts.len() > 7 {
132+
Self::verify_execution_delegate(
133+
ctx.asset_info.unwrap().key,
134+
ctx.authority_info.key,
135+
ctx.accounts.get(7).unwrap(),
136+
)
137+
} else {
138+
abstain!()
139+
}
107140
}
108141
}
109142

programs/mpl-core/src/processor/execute.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,28 @@ pub(crate) fn execute<'a>(accounts: &'a [AccountInfo<'a>], args: ExecuteV1Args)
8080
&[ctx.accounts.payer.clone(), ctx.accounts.asset.clone()],
8181
)?;
8282

83+
// If the first remaining account is an ExecutionDelegateRecordV1, strip it
84+
// before passing to the CPI -- it was only needed for plugin validation.
85+
let cpi_accounts = if let Some(first) = ctx.remaining_accounts.first() {
86+
if first.owner == &mpl_agent_tools::ID
87+
&& first.data_len() > 0
88+
&& first.data.borrow()[0]
89+
== mpl_agent_tools::types::Key::ExecutionDelegateRecordV1 as u8
90+
{
91+
&ctx.remaining_accounts[1..]
92+
} else {
93+
ctx.remaining_accounts
94+
}
95+
} else {
96+
ctx.remaining_accounts
97+
};
98+
8399
process_execute(
84100
ctx.accounts.asset.key,
85101
ctx.accounts.asset_signer.key,
86102
ctx.accounts.program_id.key,
87103
args.instruction_data,
88-
ctx.remaining_accounts,
104+
cpi_accounts,
89105
)
90106
}
91107

0 commit comments

Comments
 (0)