Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dex operations #1

Merged
merged 8 commits into from
Dec 3, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ crate-type = ["cdylib"]
candid = "0.10"
ic-cdk = "0.13"
ic-cdk-macros = "0.13"
serde = { version = "1.0", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
num-traits = "0.2"
sha2 = "0.10"
leb128 = "0.2"
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
type CurrencyPair = record {
base_currency: text;
quote_currency: text;
};

type MintOperation = record {
currency: text;
amount: nat;
recipient: principal;
};

type BurnOperation = record {
currency: text;
amount: nat;
owner: principal;
};

type Value = variant {
Blob : blob;
Text : text;
Expand Down Expand Up @@ -40,4 +57,4 @@ service : {
icrc3_get_tip_certificate : () -> (opt DataCertificate) query;
icrc3_get_blocks : (GetBlocksArgs) -> (GetBlocksResult) query;
icrc3_supported_block_types : () -> (vec record { block_type : text; url : text }) query;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub const INCREMENT_OPERATION: &str = "increment";
pub const GET_OPERATION: &str = "get";
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use crate::state::STATE;
use crate::logging::log_operation;
use crate::constants::{INCREMENT_OPERATION, GET_OPERATION};
use ic_cdk_macros::*;

/// Increments the counter and logs the operation.
///
/// # Returns
///
/// * `u64` - The new value of the counter after incrementing.
#[update]
pub async fn increment() -> u64 {
let new_value = STATE.with(|state| {
let mut state = state.borrow_mut();
state.counter += 1;
state.counter
});

let _ = log_operation(INCREMENT_OPERATION, new_value).await;
new_value
}

/// Gets the current value of the counter and logs the operation.
///
/// # Returns
///
/// * `u64` - The current value of the counter.
#[update]
pub async fn get() -> u64 {
let value = STATE.with(|state| state.borrow().counter);
let _ = log_operation(GET_OPERATION, value).await;
value
}
168 changes: 168 additions & 0 deletions canisters/counter_canister/src/counter_canister_backend/src/icrc3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
use candid::{ Principal, Nat};
use serde::Serialize;
use ic_cdk_macros::*;
use num_traits::cast::ToPrimitive;
use sha2::{Sha256, Digest};

use crate::types::{
GetArchivesArgs, GetArchivesResult, ArchiveInfo,
DataCertificate, GetBlocksArgs, GetBlocksResult,
BlockInfo, ArchivedBlocksRange, Value, BlockTypeInfo
};
use crate::state::BLOCKS;

// Note: These are stub implementations for Proof of Concept (PoC) purposes only.

impl Serialize for ArchivedBlocksRange {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;
let mut state = serializer.serialize_struct("ArchivedBlocksRange", 2)?;
state.serialize_field("args", &self.args)?;
state.serialize_field("callback", &self.callback)?;
state.end()
}
}

// ICRC-3 Interface Implementations

/// Retrieves information about archives.
///
/// # Arguments
///
/// * `args` - A `GetArchivesArgs` struct containing optional starting principal.
///
/// # Returns
///
/// * `ArchiveInfo` - Information about the archive, including canister ID and block range.
#[query]
pub fn icrc3_get_archives(args: GetArchivesArgs) -> GetArchivesResult {
// Mock implementation
let archives = vec![
ArchiveInfo {
canister_id: Principal::from_text("aaaaa-aa").unwrap_or_else(|_| Principal::anonymous()),
start: Nat::from(0u64),
end: Nat::from(999u64),
},
ArchiveInfo {
canister_id: Principal::from_text("bbbbb-bb").unwrap_or_else(|_| Principal::anonymous()),
start: Nat::from(1000u64),
end: Nat::from(1999u64),
},
];

// If 'from' is provided, return archives starting from that canister
let filtered_archives = match args.from {
Some(from) => archives.into_iter().skip_while(|info| info.canister_id != from).collect(),
None => archives,
};

GetArchivesResult(filtered_archives)
}

/// Retrieves the tip certificate for data integrity verification.
///
/// # Returns
///
/// * `Option<DataCertificate>` - The tip certificate if available, or None.
#[query]
pub fn icrc3_get_tip_certificate() -> Option<DataCertificate> {
BLOCKS.with(|blocks| {
let blocks = blocks.borrow();
if blocks.is_empty() {
return None;
}

let last_block = blocks.last().unwrap();
let last_block_index = Nat::from(blocks.len() - 1);

let mut hasher = Sha256::new();
let mut certificate_data = Vec::new();

let mut leb_encoded = Vec::new();
let block_index = last_block_index.0.to_u64().unwrap_or(0);
leb128::write::unsigned(&mut leb_encoded, block_index).unwrap();

certificate_data.extend_from_slice(&leb_encoded);
certificate_data.extend_from_slice(&last_block.hash);

hasher.update(&certificate_data);
let hash_tree = hasher.finalize().to_vec();

Some(DataCertificate {
certificate: certificate_data,
hash_tree,
})
})
}

/// Retrieves blocks within a specified range.
///
/// # Arguments
///
/// * `args` - A `GetBlocksArgs` struct specifying the start and length of the block range.
///
/// # Returns
///
/// * `GetBlocksResult` - The result containing log length, blocks, and archived block ranges.
#[query]
pub fn icrc3_get_blocks(args: GetBlocksArgs) -> GetBlocksResult {
let start = args.start.0.to_u64().unwrap_or(0);
let length = args.length.0.to_u64().unwrap_or(0);

BLOCKS.with(|blocks| {
let blocks = blocks.borrow();
let log_length = blocks.len() as u64;
let blocks = blocks.iter()
.skip(start as usize)
.take(length as usize)
.enumerate()
.map(|(index, block)| BlockInfo {
id: Nat::from(start + index as u64),
block: Value::Map(vec![
("id".to_string(), Value::Nat(block.id.clone())),
("hash".to_string(), Value::Blob(block.hash.clone())),
("phash".to_string(), Value::Blob(block.phash.clone())),
("btype".to_string(), Value::Text(block.btype.clone())),
("ts".to_string(), Value::Nat(Nat::from(block.ts))),
("finalized".to_string(), Value::Text(block.finalized.to_string())),
("entries".to_string(), Value::Array(block.entries.iter().map(|entry| {
Value::Map(vec![
("timestamp".to_string(), Value::Nat(Nat::from(entry.timestamp))),
("operation".to_string(), Value::Text(entry.operation.clone())),
("details".to_string(), entry.details.clone()),
("caller".to_string(), Value::Text(entry.caller.clone())),
])
}).collect())),
])
})
.collect();

// NOTE: For PoC purposes, we're not actually implementing archived blocks.
// In a real implementation, this would check for and return actual archived blocks.
let archived_blocks = vec![];

GetBlocksResult {
log_length: Nat::from(log_length),
blocks,
archived_blocks,
}
})
}

/// Returns supported block types.
///
/// # Returns
///
/// * `Vec<BlockTypeInfo>` - A vector of supported block types and their corresponding URLs.
#[query]
pub fn icrc3_supported_block_types() -> Vec<BlockTypeInfo> {
vec![
BlockTypeInfo {
block_type: "log_entry".to_string(),
url: "https://github.com/dfinity/ICRC-1/blob/main/standards/ICRC-3/README.md".to_string(),
}
]
}
Loading
Loading