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
39 changes: 39 additions & 0 deletions artifacts/amm-idl.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,41 @@
{
"name": "token_program_id",
"type": "program_id"
},
{
"name": "authority",
"type": "account_id"
}
]
},
{
"name": "update_config",
"accounts": [
{
"name": "config",
"writable": false,
"signer": false,
"init": false
},
{
"name": "authority",
"writable": false,
"signer": false,
"init": false
}
],
"args": [
{
"name": "token_program_id",
"type": {
"option": "program_id"
}
},
{
"name": "new_authority",
"type": {
"option": "account_id"
}
}
]
},
Expand Down Expand Up @@ -434,6 +469,10 @@
{
"name": "token_program_id",
"type": "program_id"
},
{
"name": "authority",
"type": "account_id"
}
]
}
Expand Down
23 changes: 22 additions & 1 deletion programs/amm/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ pub enum Instruction {
///
/// The configuration account is a PDA derived from the constant `"CONFIG"` seed
/// (`compute_config_pda(self_program_id)`). It stores the Token Program ID that the AMM
/// uses for every chained call. The Program must be initialized via this instruction before
/// uses for every chained call, plus the admin `authority` allowed to change configuration
/// later via `UpdateConfig`. The Program must be initialized via this instruction before
/// any pool can be created or interacted with — the other instructions read the Token
/// Program ID from this account and reject calls when it does not yet exist.
///
Expand All @@ -29,6 +30,24 @@ pub enum Instruction {
Initialize {
/// Program ID of the Token Program the AMM will issue chained calls to.
token_program_id: ProgramId,
/// Admin authority allowed to change configuration via `UpdateConfig`.
authority: AccountId,
},

/// Updates the AMM Program's configuration. Only the configured admin `authority` may call
/// this; the authority account must be passed authorized (signed).
///
/// Each field is optional — `None` leaves the corresponding value unchanged. Setting
/// `new_authority` transfers admin control to a different account.
///
/// Required accounts:
/// - AMM Config Account (initialized)
/// - Authority Account — must equal the config's current `authority`, passed authorized.
UpdateConfig {
/// New Token Program ID for chained calls, or `None` to keep the current one.
token_program_id: Option<ProgramId>,
/// New admin authority (transfers control), or `None` to keep the current admin.
new_authority: Option<AccountId>,
},

/// Initializes a new Pool (or re-initializes an existing zero-supply Pool).
Expand Down Expand Up @@ -204,6 +223,8 @@ impl From<&PoolDefinition> for Data {
pub struct AmmConfig {
/// Program ID of the Token Program the AMM issues chained calls to.
pub token_program_id: ProgramId,
/// Admin authority allowed to change this configuration via `UpdateConfig`.
pub authority: AccountId,
}
Comment thread
0x-r4bbit marked this conversation as resolved.

impl TryFrom<&Data> for AmmConfig {
Expand Down
32 changes: 30 additions & 2 deletions programs/amm/methods/guest/src/bin/amm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,37 @@ mod amm {
ctx: ProgramContext,
config: AccountWithMetadata,
token_program_id: ProgramId,
authority: AccountId,
) -> SpelResult {
let post_states =
amm_program::initialize::initialize(config, token_program_id, ctx.self_program_id);
let post_states = amm_program::initialize::initialize(
config,
token_program_id,
authority,
ctx.self_program_id,
);
Ok(spel_framework::SpelOutput::execute(post_states, vec![]))
}

/// Updates the AMM Program's configuration. Only the configured admin authority may call this.
///
/// Expected accounts:
/// 1. `config` — initialized AMM config account.
/// 2. `authority` — the config's current admin, passed authorized (signed).
#[instruction]
pub fn update_config(
ctx: ProgramContext,
config: AccountWithMetadata,
authority: AccountWithMetadata,
token_program_id: Option<ProgramId>,
new_authority: Option<AccountId>,
) -> SpelResult {
let post_states = amm_program::update_config::update_config(
config,
authority,
token_program_id,
new_authority,
ctx.self_program_id,
);
Ok(spel_framework::SpelOutput::execute(post_states, vec![]))
}

Expand Down
39 changes: 30 additions & 9 deletions programs/amm/src/initialize.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use amm_core::{compute_config_pda, compute_config_pda_seed, AmmConfig};
use nssa_core::{
account::{Account, AccountWithMetadata, Data},
account::{Account, AccountId, AccountWithMetadata, Data},
program::{AccountPostState, Claim, ProgramId},
};

/// Initializes the AMM Program by creating its singleton configuration account.
///
/// The config account is a PDA derived from the constant `"CONFIG"` seed
/// (`compute_config_pda(amm_program_id)`) and stores `token_program_id`, the Token Program the
/// AMM issues every chained call to. Its existence is the Program's "initialized" flag: the
/// (`compute_config_pda(amm_program_id)`) and stores `token_program_id` (the Token Program the
/// AMM issues every chained call to) and `authority` (the admin allowed to change configuration
/// later via `update_config`). Its existence is the Program's "initialized" flag: the
/// chained-call instructions read the Token Program ID from it and reject calls until it exists.
///
/// # Panics
Expand All @@ -18,6 +19,7 @@ use nssa_core::{
pub fn initialize(
config: AccountWithMetadata,
token_program_id: ProgramId,
authority: AccountId,
amm_program_id: ProgramId,
) -> Vec<AccountPostState> {
Comment thread
0x-r4bbit marked this conversation as resolved.
assert_eq!(
Expand All @@ -32,7 +34,10 @@ pub fn initialize(
);

let mut config_post = config.account.clone();
config_post.data = Data::from(&AmmConfig { token_program_id });
config_post.data = Data::from(&AmmConfig {
token_program_id,
authority,
});

vec![AccountPostState::new_claimed(
config_post,
Expand All @@ -50,6 +55,10 @@ mod tests {
const AMM_PROGRAM_ID: ProgramId = [42; 8];
const TOKEN_PROGRAM_ID: ProgramId = [15; 8];

fn authority() -> AccountId {
AccountId::new([9; 32])
}

fn config_uninit() -> AccountWithMetadata {
AccountWithMetadata {
account: Account::default(),
Expand All @@ -60,7 +69,12 @@ mod tests {

#[test]
fn returns_single_pda_claimed_post_state() {
let post_states = initialize(config_uninit(), TOKEN_PROGRAM_ID, AMM_PROGRAM_ID);
let post_states = initialize(
config_uninit(),
TOKEN_PROGRAM_ID,
authority(),
AMM_PROGRAM_ID,
);
assert_eq!(post_states.len(), 1);
assert_eq!(
post_states[0].required_claim(),
Expand All @@ -69,19 +83,25 @@ mod tests {
}

#[test]
fn stores_token_program_id() {
let post_states = initialize(config_uninit(), TOKEN_PROGRAM_ID, AMM_PROGRAM_ID);
fn stores_token_program_id_and_authority() {
let post_states = initialize(
config_uninit(),
TOKEN_PROGRAM_ID,
authority(),
AMM_PROGRAM_ID,
);
let config = AmmConfig::try_from(&post_states[0].account().data)
.expect("post state must contain a valid AmmConfig");
assert_eq!(config.token_program_id, TOKEN_PROGRAM_ID);
assert_eq!(config.authority, authority());
}

#[test]
#[should_panic(expected = "AMM config Account ID does not match PDA")]
fn wrong_config_account_id_panics() {
let mut wrong = config_uninit();
wrong.account_id = AccountId::new([0; 32]);
initialize(wrong, TOKEN_PROGRAM_ID, AMM_PROGRAM_ID);
initialize(wrong, TOKEN_PROGRAM_ID, authority(), AMM_PROGRAM_ID);
}

#[test]
Expand All @@ -90,8 +110,9 @@ mod tests {
let mut initialized = config_uninit();
initialized.account.data = Data::from(&AmmConfig {
token_program_id: TOKEN_PROGRAM_ID,
authority: authority(),
});
initialized.account.nonce = Nonce(0);
initialize(initialized, TOKEN_PROGRAM_ID, AMM_PROGRAM_ID);
initialize(initialized, TOKEN_PROGRAM_ID, authority(), AMM_PROGRAM_ID);
}
}
1 change: 1 addition & 0 deletions programs/amm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ pub mod new_definition;
pub mod remove;
pub mod swap;
pub mod sync;
pub mod update_config;

mod tests;
1 change: 1 addition & 0 deletions programs/amm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ impl AccountWithMetadataForTests {
balance: 0u128,
data: Data::from(&AmmConfig {
token_program_id: TOKEN_PROGRAM_ID,
authority: AccountId::new([9; 32]),
}),
nonce: Nonce(0),
},
Expand Down
Loading
Loading