Skip to content

Commit

Permalink
add token manager logic
Browse files Browse the repository at this point in the history
  • Loading branch information
glihm committed Sep 13, 2023
1 parent a123adc commit b35e288
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 95 deletions.
3 changes: 2 additions & 1 deletion crates/ark-starknet/src/client2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ impl StarknetClient {
Ok(events)
}

///
/// Call a contract trying all the given selectors.
/// All selector must accept the same arguments.
pub async fn call_contract(
&self,
contract_address: FieldElement,
Expand Down
29 changes: 14 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
mod constants;
mod contract;
mod managers;
mod storage;
mod transfer;
mod utils;

use anyhow::Result;
use ark_starknet::client2::StarknetClient;
use dotenv::dotenv;
use managers::collection_manager::ContractType;
use managers::{BlockManager, CollectionManager, EventManager};
use managers::{BlockManager, CollectionManager, EventManager, TokenManager};
use starknet::core::types::*;
use std::env;
use tokio::time::{self, Duration};
use tracing::{span, Level};
use tracing_subscriber::{fmt, layer::SubscriberExt, EnvFilter, Registry};

use starknet::core::types::*;
use tokio::time::{self, Duration};

mod storage;

#[tokio::main]
async fn main() -> Result<()> {
dotenv().ok();
Expand All @@ -29,6 +27,7 @@ async fn main() -> Result<()> {
let storage = storage::init_default();
let block_manager = BlockManager::new(&storage, &sn_client);
let mut event_manager = EventManager::new(&storage, &sn_client);
let mut token_manager = TokenManager::new(&storage, &sn_client);
let mut collection_manager = CollectionManager::new(&storage, &sn_client);

let (from_block, to_block, poll_head_of_chain) = block_manager.get_block_range();
Expand Down Expand Up @@ -76,13 +75,7 @@ async fn main() -> Result<()> {
continue;
}

log::debug!(
"Contract type [{:#064x}] : {}",
contract_address,
contract_type.to_string()
);

let _token_id = match event_manager
let token_event = match event_manager
.format_event(&e, contract_type, block_ts)
.await
{
Expand All @@ -93,7 +86,13 @@ async fn main() -> Result<()> {
}
};

// token_manager.register_token(...);
match token_manager.format_token(&token_event).await {
Ok(()) => (),
Err(err) => {
log::error!("Can't format token {:?}\ntevent: {:?}", err, token_event);
continue;
}
}
}
}

Expand Down Expand Up @@ -126,7 +125,7 @@ async fn check_range(
.await
.expect("Can't fetch last block number");

Check warning on line 126 in src/main.rs

View workflow job for this annotation

GitHub Actions / clippy

unneeded `return` statement

warning: unneeded `return` statement --> src/main.rs:123:9 | 123 | / return client 124 | | .block_number() 125 | | .await 126 | | .expect("Can't fetch last block number"); | |____________________________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return help: remove `return` | 123 ~ client 124 + .block_number() 125 + .await 126 ~ .expect("Can't fetch last block number") |
} else {
return current;
return to;

Check warning on line 128 in src/main.rs

View workflow job for this annotation

GitHub Actions / clippy

unneeded `return` statement

warning: unneeded `return` statement --> src/main.rs:128:9 | 128 | return to; | ^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return help: remove `return` | 128 - return to; 128 + to |
}
}

Expand Down
63 changes: 9 additions & 54 deletions src/managers/collection_manager.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use anyhow::{anyhow, Result};
use ark_starknet::client2::StarknetClient;
use ark_storage::storage_manager::StorageManager;
use log::info;

use serde::{Deserialize, Serialize};
use starknet::core::types::{BlockId, BlockTag, FieldElement};
use starknet::core::utils::{get_selector_from_name, parse_cairo_short_string};
use starknet::macros::selector;

use std::collections::HashMap;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
Expand Down Expand Up @@ -74,6 +74,12 @@ impl<'a, T: StorageManager> CollectionManager<'a, T> {
// Can't find info, try to identify with calls.
let contract_type = self.get_contract_type(address).await?;

log::debug!(
"Contract type [{:#064x}] : {}",
address,
contract_type.to_string()
);

let info = ContractInfo {
name: String::new(),
symbol: String::new(),
Expand All @@ -82,61 +88,12 @@ impl<'a, T: StorageManager> CollectionManager<'a, T> {

self.cache.insert(address, info.clone());
// TODO: self.storage.register_contract_info(...);

Ok(info)
}
}
}

pub async fn get_token_owner(
&self,
contract_address: FieldElement,
token_id_low: FieldElement,
token_id_high: FieldElement,
) -> Result<Vec<FieldElement>> {
let block = BlockId::Tag(BlockTag::Latest);

match self
.client
.call_contract(
contract_address,
selector!("owner_of"),
vec![token_id_low, token_id_high],
block,
)
.await
{
Ok(res) => Ok(res),
Err(_) => self
.client
.call_contract(
contract_address,
selector!("owner_of"),
vec![token_id_low, token_id_high],
block,
)
.await
.map_err(|_| anyhow!("Failed to get token owner")),
}
}

async fn call_contract_helper(
&self,
contract_address: FieldElement,
selector_name: &str,
token_id_low: FieldElement,
token_id_high: FieldElement,
block_id: BlockId,
) -> Result<Vec<FieldElement>> {
self.client
.call_contract(
contract_address,
get_selector_from_name(selector_name)?,
vec![token_id_low, token_id_high],
block_id,
)
.await
}

pub async fn get_contract_type(&self, contract_address: FieldElement) -> Result<ContractType> {
let block = BlockId::Tag(BlockTag::Latest);
let token_uri_cairo_0 = self
Expand Down Expand Up @@ -182,8 +139,6 @@ impl<'a, T: StorageManager> CollectionManager<'a, T> {
calldata: Vec<FieldElement>,
block: BlockId,
) -> Result<String> {
info!("Getting contract property: {:?}", selector_name);

let response = self
.client
.call_contract(
Expand Down
4 changes: 2 additions & 2 deletions src/managers/event_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl<'a, T: StorageManager> EventManager<'a, T> {
event: &EmittedEvent,
contract_type: ContractType,
timestamp: u64,
) -> Result<TokenId> {
) -> Result<TokenEvent> {
self.reset_event();

// As cairo didn't have keys before, we first check if the data
Expand Down Expand Up @@ -75,7 +75,7 @@ impl<'a, T: StorageManager> EventManager<'a, T> {
// TODO: self.storage.register_event(self.token_event);
// TODO: check depending on event type if it's a create/update etc...?

Ok(token_id)
Ok(self.token_event.clone())
}

pub fn get_event_type(from: FieldElement, to: FieldElement) -> EventType {
Expand Down
90 changes: 67 additions & 23 deletions src/managers/token_manager.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
use anyhow::Result;
use anyhow::{anyhow, Result};
use ark_starknet::client2::StarknetClient;
use ark_storage::storage_manager::StorageManager;
use ark_storage::types::{EventType, TokenEvent, TokenFromEvent};
use starknet::core::types::*;
use starknet::macros::selector;

#[derive(Debug)]
pub struct TokenManager<'a, T: StorageManager> {
storage: &'a T,

Check warning on line 10 in src/managers/token_manager.rs

View workflow job for this annotation

GitHub Actions / clippy

field `storage` is never read

warning: field `storage` is never read --> src/managers/token_manager.rs:10:5 | 9 | pub struct TokenManager<'a, T: StorageManager> { | ------------ field in this struct 10 | storage: &'a T, | ^^^^^^^ | = note: `TokenManager` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
client: &'a StarknetClient,
// TODO: Same as event manager, we should use the stack instead.
// check with @kwiss.
token: TokenFromEvent,
// client: StarknetClient,
}

impl<'a, T: StorageManager> TokenManager<'a, T> {
pub fn new(
storage: &'a T,
// client: StarknetClient
) -> Self {
/// Initializes a new instance.
pub fn new(storage: &'a T, client: &'a StarknetClient) -> Self {
Self {
storage,
client,
token: TokenFromEvent::default(),
// client
}
}

pub fn format_token_from_event(&mut self, event: &TokenEvent) {
/// Formats a token registry from the token event data.
pub async fn format_token(&mut self, event: &TokenEvent) -> Result<()> {
self.reset_token();

self.token.address = event.contract_address.clone();
self.token.padded_token_id = event.padded_token_id.clone();
self.token.from_address = event.from_address.clone();
self.token.to_address = event.to_address.clone();
self.token.timestamp = event.timestamp.clone();

Check warning on line 35 in src/managers/token_manager.rs

View workflow job for this annotation

GitHub Actions / clippy

using `clone` on type `u64` which implements the `Copy` trait

warning: using `clone` on type `u64` which implements the `Copy` trait --> src/managers/token_manager.rs:35:32 | 35 | self.token.timestamp = event.timestamp.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the `clone` call: `event.timestamp` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy = note: `#[warn(clippy::clone_on_copy)]` on by default
// TODO update owner here call get_token_owner
self.token.owner = event.to_address.clone();
self.token.mint_transaction_hash = if event.event_type == EventType::Mint {
Some(event.transaction_hash.clone())
} else {
Expand All @@ -39,26 +43,66 @@ impl<'a, T: StorageManager> TokenManager<'a, T> {
} else {
None
};
}

pub fn create_token(&self) -> Result<()> {
self.storage.create_token(&self.token);
// TODO: @kwiss, do we want a default value in case we can't get the token owner?
// or do we want to return an error and abort before saving in the storage?
let token_owner = self
.get_token_owner(
FieldElement::from_hex_be(&event.contract_address)
.expect("Contract address bad format"),
FieldElement::from(event.token_id.low),

Check warning on line 53 in src/managers/token_manager.rs

View workflow job for this annotation

GitHub Actions / clippy

useless conversion to the same type: `starknet::core::types::FieldElement`

warning: useless conversion to the same type: `starknet::core::types::FieldElement` --> src/managers/token_manager.rs:53:17 | 53 | FieldElement::from(event.token_id.low), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `FieldElement::from()`: `event.token_id.low` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion = note: `#[warn(clippy::useless_conversion)]` on by default
FieldElement::from(event.token_id.high),

Check warning on line 54 in src/managers/token_manager.rs

View workflow job for this annotation

GitHub Actions / clippy

useless conversion to the same type: `starknet::core::types::FieldElement`

warning: useless conversion to the same type: `starknet::core::types::FieldElement` --> src/managers/token_manager.rs:54:17 | 54 | FieldElement::from(event.token_id.high), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `FieldElement::from()`: `event.token_id.high` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
)
.await?[0];

self.token.owner = format!("{:#064x}", token_owner);

log::trace!(
"Registering token: {} {}",
event.token_id.format().token_id,
event.contract_address
);

// TODO: self.storage.register_token(self.token.clone()).await?;

Ok(())
}

///
pub fn reset_token(&mut self) {
self.token = TokenFromEvent::default();
}

// pub fn get_token_owner(&self) -> TokenFromEvent {
// TODO call contract to get owner
// }
/// Retrieves the token owner for the last block.
pub async fn get_token_owner(
&self,
contract_address: FieldElement,
token_id_low: FieldElement,
token_id_high: FieldElement,
) -> Result<Vec<FieldElement>> {
let block = BlockId::Tag(BlockTag::Latest);

// pub fn update_token_owner(&self) -> Result<()> {
// let token = self
// .storage
// .get_token(event.contract_address.clone(), event.token_id.clone())?;
// self.storage.update_token_owner(&token);
// Ok(())
// }
match self
.client
.call_contract(
contract_address,
selector!("owner_of"),
vec![token_id_low, token_id_high],
block,
)
.await
{
Ok(res) => Ok(res),
Err(_) => self
.client
.call_contract(
contract_address,
selector!("ownerOf"),
vec![token_id_low, token_id_high],
block,
)
.await
.map_err(|_| anyhow!("Failed to get token owner from chain")),
}
}
}

0 comments on commit b35e288

Please sign in to comment.