Skip to content

Commit

Permalink
Disallow P2P swaps of disabled tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
hpeebles committed Dec 13, 2024
1 parent b32e38a commit b31130d
Show file tree
Hide file tree
Showing 22 changed files with 229 additions and 14 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/canisters/escrow/api/src/lifecycle/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use types::{BuildVersion, CanisterId};

#[derive(CandidType, Serialize, Deserialize, Debug)]
pub struct Args {
pub registry_canister_id: CanisterId,
pub cycles_dispenser_canister_id: CanisterId,
pub wasm_version: BuildVersion,
pub test_mode: bool,
Expand Down
14 changes: 14 additions & 0 deletions backend/canisters/escrow/api/src/updates/c2c_set_token_enabled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use candid::CandidType;
use serde::{Deserialize, Serialize};
use types::CanisterId;

#[derive(CandidType, Serialize, Deserialize, Debug)]
pub struct Args {
pub ledger_canister_id: CanisterId,
pub enabled: bool,
}

#[derive(CandidType, Serialize, Deserialize, Debug)]
pub enum Response {
Success,
}
1 change: 1 addition & 0 deletions backend/canisters/escrow/api/src/updates/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod c2c_set_token_enabled;
pub mod cancel_swap;
pub mod create_swap;
pub mod notify_deposit;
1 change: 1 addition & 0 deletions backend/canisters/escrow/c2c_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use escrow_canister::*;
// Queries

// Updates
generate_c2c_call!(c2c_set_token_enabled);
generate_c2c_call!(create_swap);
generate_c2c_call!(cancel_swap);
generate_c2c_call!(notify_deposit);
9 changes: 9 additions & 0 deletions backend/canisters/escrow/impl/src/guards.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use crate::read_state;

pub fn caller_is_registry_canister() -> Result<(), String> {
if read_state(|state| state.is_caller_registry_canister()) {
Ok(())
} else {
Err("Caller is not the registry canister".to_string())
}
}
19 changes: 17 additions & 2 deletions backend/canisters/escrow/impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use canister_state_macros::canister_state;
use canister_timer_jobs::TimerJobs;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, BTreeSet};
use types::{BuildVersion, CanisterId, Cycles, TimestampMillis, Timestamped};
use utils::env::Environment;

mod guards;
mod jobs;
mod lifecycle;
mod memory;
Expand All @@ -34,6 +35,10 @@ impl RuntimeState {
RuntimeState { env, data }
}

pub fn is_caller_registry_canister(&self) -> bool {
self.env.caller() == self.data.registry_canister_id
}

pub fn metrics(&self) -> Metrics {
let now = self.env.now();

Expand All @@ -46,7 +51,9 @@ impl RuntimeState {
git_commit_id: utils::git::git_commit_id().to_string(),
swaps: self.data.swaps.metrics(now),
stable_memory_sizes: memory::memory_sizes(),
disabled_tokens: self.data.disabled_tokens.iter().copied().collect(),
canister_ids: CanisterIds {
registry: self.data.registry_canister_id,
cycles_dispenser: self.data.cycles_dispenser_canister_id,
},
}
Expand All @@ -59,19 +66,25 @@ struct Data {
pub pending_payments_queue: PendingPaymentsQueue,
pub notify_status_change_queue: NotifyStatusChangeQueue,
timer_jobs: TimerJobs<TimerJob>,
#[serde(default = "CanisterId::anonymous")]
pub registry_canister_id: CanisterId,
pub cycles_dispenser_canister_id: CanisterId,
#[serde(default)]
pub disabled_tokens: BTreeSet<CanisterId>,
pub rng_seed: [u8; 32],
pub test_mode: bool,
}

impl Data {
pub fn new(cycles_dispenser_canister_id: CanisterId, test_mode: bool) -> Data {
pub fn new(registry_canister_id: CanisterId, cycles_dispenser_canister_id: CanisterId, test_mode: bool) -> Data {
Data {
swaps: Swaps::default(),
pending_payments_queue: PendingPaymentsQueue::default(),
notify_status_change_queue: NotifyStatusChangeQueue::default(),
timer_jobs: TimerJobs::default(),
registry_canister_id,
cycles_dispenser_canister_id,
disabled_tokens: BTreeSet::new(),
rng_seed: [0; 32],
test_mode,
}
Expand All @@ -88,6 +101,7 @@ pub struct Metrics {
pub git_commit_id: String,
pub swaps: SwapMetrics,
pub stable_memory_sizes: BTreeMap<u8, u64>,
pub disabled_tokens: Vec<CanisterId>,
pub canister_ids: CanisterIds,
}

Expand All @@ -103,5 +117,6 @@ pub struct SwapMetrics {

#[derive(Serialize, Debug)]
pub struct CanisterIds {
pub registry: CanisterId,
pub cycles_dispenser: CanisterId,
}
2 changes: 1 addition & 1 deletion backend/canisters/escrow/impl/src/lifecycle/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn init(args: Args) {
init_cycles_dispenser_client(args.cycles_dispenser_canister_id, args.test_mode);

let env = init_env([0; 32]);
let data = Data::new(args.cycles_dispenser_canister_id, args.test_mode);
let data = Data::new(args.registry_canister_id, args.cycles_dispenser_canister_id, args.test_mode);

init_state(env, data, args.wasm_version);

Expand Down
9 changes: 8 additions & 1 deletion backend/canisters/escrow/impl/src/lifecycle/post_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use escrow_canister::post_upgrade::Args;
use ic_cdk::post_upgrade;
use stable_memory::get_reader;
use tracing::info;
use types::CanisterId;
use utils::cycles::init_cycles_dispenser_client;

#[post_upgrade]
Expand All @@ -15,7 +16,13 @@ fn post_upgrade(args: Args) {
let memory = get_upgrades_memory();
let reader = get_reader(&memory);

let (data, logs, traces): (Data, Vec<LogEntry>, Vec<LogEntry>) = msgpack::deserialize(reader).unwrap();
let (mut data, logs, traces): (Data, Vec<LogEntry>, Vec<LogEntry>) = msgpack::deserialize(reader).unwrap();

if data.test_mode {
data.registry_canister_id = CanisterId::from_text("cglwi-oaaaa-aaaar-aqw4q-cai").unwrap();
} else {
data.registry_canister_id = CanisterId::from_text("cpi5u-yiaaa-aaaar-aqw5a-cai").unwrap();
}

// TODO: After release change this to
// let (data, errors, logs, traces): (Data, Vec<LogEntry>, Vec<LogEntry>, Vec<LogEntry>) = msgpack::deserialize(reader).unwrap();
Expand Down
20 changes: 20 additions & 0 deletions backend/canisters/escrow/impl/src/updates/c2c_set_token_enabled.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::guards::caller_is_registry_canister;
use crate::{mutate_state, RuntimeState};
use canister_api_macros::update;
use canister_tracing_macros::trace;
use escrow_canister::c2c_set_token_enabled::{Response::*, *};

#[update(guard = "caller_is_registry_canister", msgpack = true)]
#[trace]
fn c2c_set_token_enabled(args: Args) -> Response {
mutate_state(|state| c2c_set_token_enabled_impl(args, state))
}

fn c2c_set_token_enabled_impl(args: Args, state: &mut RuntimeState) -> Response {
if args.enabled {
state.data.disabled_tokens.remove(&args.ledger_canister_id);
} else {
state.data.disabled_tokens.insert(args.ledger_canister_id);
}
Success
}
16 changes: 10 additions & 6 deletions backend/canisters/escrow/impl/src/updates/create_swap.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::timer_job_types::{ExpireSwapJob, TimerJob};
use crate::{mutate_state, RuntimeState};
use crate::{mutate_state, Data, RuntimeState};
use canister_api_macros::update;
use canister_tracing_macros::trace;
use escrow_canister::create_swap::{Response::*, *};
Expand All @@ -13,7 +13,7 @@ fn create_swap(args: Args) -> Response {

fn create_swap_impl(args: Args, state: &mut RuntimeState) -> Response {
let now = state.env.now();
if let Err(error) = validate_swap(&args, now) {
if let Err(error) = validate_swap(&args, now, &state.data) {
InvalidSwap(error)
} else {
let caller = state.env.caller().into();
Expand All @@ -28,15 +28,19 @@ fn create_swap_impl(args: Args, state: &mut RuntimeState) -> Response {
}
}

fn validate_swap(args: &Args, now: TimestampMillis) -> Result<(), String> {
fn validate_swap(args: &Args, now: TimestampMillis, data: &Data) -> Result<(), String> {
if args.token0.ledger == args.token1.ledger {
Err("Token0 must be different to token1".to_string())
Err("Input token must be different to output token".to_string())
} else if args.token0_amount == 0 {
Err("Token0 amount cannot be 0".to_string())
Err("Input amount cannot be 0".to_string())
} else if args.token1_amount == 0 {
Err("Token1 amount cannot be 0".to_string())
Err("Output amount cannot be 0".to_string())
} else if args.expires_at < now {
Err("Expiry cannot be in the past".to_string())
} else if data.disabled_tokens.contains(&args.token0.ledger) {
Err("Input token is disabled for swaps".to_string())
} else if data.disabled_tokens.contains(&args.token1.ledger) {
Err("Output token is disabled for swaps".to_string())
} else {
Ok(())
}
Expand Down
1 change: 1 addition & 0 deletions backend/canisters/escrow/impl/src/updates/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod c2c_set_token_enabled;
pub mod cancel_swap;
pub mod create_swap;
pub mod notify_deposit;
Expand Down
1 change: 1 addition & 0 deletions backend/canisters/registry/api/src/lifecycle/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub struct Args {
pub nns_root_canister_id: CanisterId,
pub sns_wasm_canister_id: CanisterId,
pub nns_index_canister_id: CanisterId,
pub escrow_canister_id: CanisterId,
pub cycles_dispenser_canister_id: CanisterId,
pub wasm_version: BuildVersion,
pub test_mode: bool,
Expand Down
2 changes: 2 additions & 0 deletions backend/canisters/registry/impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ canister_state_macros = { path = "../../../libraries/canister_state_macros" }
canister_tracing_macros = { path = "../../../libraries/canister_tracing_macros" }
constants = { path = "../../../libraries/constants" }
dataurl = { workspace = true }
escrow_canister = { path = "../../escrow/api" }
escrow_canister_c2c_client = { path = "../../escrow/c2c_client" }
futures = { workspace = true }
hex = { workspace = true }
http_request = { path = "../../../libraries/http_request" }
Expand Down
6 changes: 6 additions & 0 deletions backend/canisters/registry/impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl RuntimeState {
canister_ids: CanisterIds {
proposals_bot: self.data.proposals_bot_canister_id,
sns_wasm: self.data.sns_wasm_canister_id,
escrow: self.data.escrow_canister_id,
cycles_dispenser: self.data.cycles_dispenser_canister_id,
},
}
Expand All @@ -75,6 +76,8 @@ struct Data {
proposals_bot_canister_id: CanisterId,
user_index_canister_id: CanisterId,
sns_wasm_canister_id: CanisterId,
#[serde(default = "CanisterId::anonymous")]
escrow_canister_id: CanisterId,
cycles_dispenser_canister_id: CanisterId,
tokens: Tokens,
nervous_systems: NervousSystems,
Expand All @@ -94,6 +97,7 @@ impl Data {
proposals_bot_canister_id: CanisterId,
user_index_canister_id: CanisterId,
sns_wasm_canister_id: CanisterId,
escrow_canister_id: CanisterId,
cycles_dispenser_canister_id: CanisterId,
test_mode: bool,
) -> Data {
Expand All @@ -102,6 +106,7 @@ impl Data {
proposals_bot_canister_id,
user_index_canister_id,
sns_wasm_canister_id,
escrow_canister_id,
cycles_dispenser_canister_id,
tokens: Tokens::default(),
nervous_systems: NervousSystems::default(),
Expand Down Expand Up @@ -184,5 +189,6 @@ pub struct Metrics {
pub struct CanisterIds {
pub proposals_bot: CanisterId,
pub sns_wasm: CanisterId,
pub escrow: CanisterId,
pub cycles_dispenser: CanisterId,
}
1 change: 1 addition & 0 deletions backend/canisters/registry/impl/src/lifecycle/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ fn init(args: Args) {
args.proposals_bot_canister_id,
args.user_index_canister_id,
args.sns_wasm_canister_id,
args.escrow_canister_id,
args.cycles_dispenser_canister_id,
args.test_mode,
);
Expand Down
40 changes: 38 additions & 2 deletions backend/canisters/registry/impl/src/lifecycle/post_upgrade.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use crate::lifecycle::{init_env, init_state};
use crate::memory::get_upgrades_memory;
use crate::Data;
use crate::{read_state, Data};
use canister_logger::LogEntry;
use canister_tracing_macros::trace;
use ic_cdk::post_upgrade;
use registry_canister::post_upgrade::Args;
use stable_memory::get_reader;
use std::time::Duration;
use tracing::info;
use types::CanisterId;
use utils::cycles::init_cycles_dispenser_client;

#[post_upgrade]
Expand All @@ -15,14 +17,48 @@ fn post_upgrade(args: Args) {
let memory = get_upgrades_memory();
let reader = get_reader(&memory);

let (data, errors, logs, traces): (Data, Vec<LogEntry>, Vec<LogEntry>, Vec<LogEntry>) =
let (mut data, errors, logs, traces): (Data, Vec<LogEntry>, Vec<LogEntry>, Vec<LogEntry>) =
msgpack::deserialize(reader).unwrap();

if data.test_mode {
data.escrow_canister_id = CanisterId::from_text("tspqt-xaaaa-aaaal-qcnna-cai").unwrap();
} else {
data.escrow_canister_id = CanisterId::from_text("s4yi7-yiaaa-aaaar-qacpq-cai").unwrap();
}

canister_logger::init_with_logs(data.test_mode, errors, logs, traces);

let env = init_env(data.rng_seed);
init_cycles_dispenser_client(data.cycles_dispenser_canister_id, data.test_mode);
init_state(env, data, args.wasm_version);

info!(version = %args.wasm_version, "Post-upgrade complete");

ic_cdk_timers::set_timer(Duration::ZERO, || ic_cdk::spawn(set_disabled_tokens_in_escrow_canister()));
}

async fn set_disabled_tokens_in_escrow_canister() {
let (disabled_tokens, escrow_canister_id) = read_state(|state| {
let disabled_tokens: Vec<_> = state
.data
.tokens
.iter()
.filter(|t| !t.enabled)
.map(|t| t.ledger_canister_id)
.collect();

(disabled_tokens, state.data.escrow_canister_id)
});

for ledger_canister_id in disabled_tokens {
escrow_canister_c2c_client::c2c_set_token_enabled(
escrow_canister_id,
&escrow_canister::c2c_set_token_enabled::Args {
ledger_canister_id,
enabled: false,
},
)
.await
.unwrap();
}
}
20 changes: 19 additions & 1 deletion backend/canisters/registry/impl/src/updates/set_token_enabled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,32 @@ use user_index_canister_c2c_client::{lookup_user, LookupUserError};
#[update(msgpack = true)]
#[trace]
async fn set_token_enabled(args: Args) -> Response {
let (caller, user_index_canister_id) = read_state(|state| (state.env.caller(), state.data.user_index_canister_id));
let (caller, user_index_canister_id, escrow_canister_id) = read_state(|state| {
(
state.env.caller(),
state.data.user_index_canister_id,
state.data.escrow_canister_id,
)
});

match lookup_user(caller, user_index_canister_id).await {
Ok(user) if user.is_platform_operator => {}
Ok(_) | Err(LookupUserError::UserNotFound) => return NotAuthorized,
Err(LookupUserError::InternalError(error)) => return InternalError(error),
}

if let Err(error) = escrow_canister_c2c_client::c2c_set_token_enabled(
escrow_canister_id,
&escrow_canister::c2c_set_token_enabled::Args {
ledger_canister_id: args.ledger_canister_id,
enabled: args.enabled,
},
)
.await
{
return InternalError(format!("Failed to update Escrow canister: {error:?}"));
}

mutate_state(|state| {
state
.data
Expand Down
Loading

0 comments on commit b31130d

Please sign in to comment.