0.7.13
This commit is contained in:
@@ -43,3 +43,4 @@
|
||||
0.7.10 - Ajout du premier support Orca Whirlpools avec décodage create_pool/swap, persistance des événements décodés et détection métier automatique pool/pair/listing
|
||||
0.7.11 - Ajout du premier support FluxBeam avec décodage create_pool/swap, persistance des événements décodés et détection métier automatique pool/pair/listing
|
||||
0.7.12 - Ajout du premier support DexLab Swap/Pool avec décodage create_pool/swap, persistance des événements décodés et détection métier automatique pool/pair/listing
|
||||
0.7.13 - Extension de la couche launch origins avec Bags et Moonit, ajout d’un enregistrement programmatique des mappings Bags, et détection automatique Moonit via suffixe de token mint
|
||||
|
||||
@@ -8,7 +8,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.7.12"
|
||||
version = "0.7.13"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"
|
||||
|
||||
14
ROADMAP.md
14
ROADMAP.md
@@ -578,15 +578,13 @@ Réalisé :
|
||||
- conservation d’une séparation entre pool DexLab natif et éventuel `OpenBook Market ID` créé ensuite.
|
||||
|
||||
### 6.045. Version `0.7.13` — Bags / Moonit comme origines de lancement
|
||||
Objectif : étendre la couche `launch origins` à d’autres surfaces au-dessus des protocoles DEX déjà intégrés.
|
||||
Réalisé :
|
||||
|
||||
À faire :
|
||||
|
||||
- ajouter `Bags` comme surface de lancement détectable,
|
||||
- ajouter `Moonit` comme surface de lancement détectable,
|
||||
- relier ces surfaces aux pools et paires finalement créés,
|
||||
- conserver une séparation stricte entre origine de lancement et protocole on-chain,
|
||||
- préparer l’extension future à d’autres launchpads ou surfaces dérivées.
|
||||
- extension de la couche `launch origins` à `Bags` et `Moonit`,
|
||||
- ajout d’un enregistrement programmatique des mappings `Bags` à partir des champs `tokenMint`, `dbcConfigKey`, `dbcPoolKey` et `dammV2PoolKey`,
|
||||
- prise en charge de l’attribution `Bags` par matching exact sur `config_account`, `pool_account` et `token_mint`,
|
||||
- prise en charge de l’attribution `Moonit` par détection automatique des token mints se terminant par `moon`,
|
||||
- conservation d’une séparation stricte entre origine de lancement et protocole on-chain.
|
||||
|
||||
### 6.046. Version `0.7.14` — Consolidation multi-DEX
|
||||
Objectif : unifier le comportement des connecteurs DEX v1 avant l’ouverture des couches analytiques plus riches.
|
||||
|
||||
@@ -30,7 +30,154 @@ impl KbLaunchOriginService {
|
||||
/// Creates a new launch-origin service.
|
||||
pub fn new(database: std::sync::Arc<crate::KbDatabase>) -> Self {
|
||||
let persistence = crate::KbDetectionPersistenceService::new(database.clone());
|
||||
Self { database, persistence }
|
||||
Self {
|
||||
database,
|
||||
persistence,
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that the built-in `moonit` launch surface exists and returns its id.
|
||||
pub async fn ensure_moonit_surface(&self) -> Result<i64, crate::KbError> {
|
||||
let existing_result =
|
||||
crate::get_launch_surface_by_code(self.database.as_ref(), "moonit").await;
|
||||
let existing_option = match existing_result {
|
||||
Ok(existing_option) => existing_option,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let surface_id = match existing_option {
|
||||
Some(existing) => match existing.id {
|
||||
Some(surface_id) => surface_id,
|
||||
None => {
|
||||
return Err(crate::KbError::InvalidState(
|
||||
"moonit launch surface has no internal id".to_string(),
|
||||
));
|
||||
}
|
||||
},
|
||||
None => {
|
||||
let dto = crate::KbLaunchSurfaceDto::new(
|
||||
"moonit".to_string(),
|
||||
"Moonit".to_string(),
|
||||
Some("launchpad".to_string()),
|
||||
true,
|
||||
);
|
||||
let insert_result =
|
||||
crate::upsert_launch_surface(self.database.as_ref(), &dto).await;
|
||||
match insert_result {
|
||||
Ok(surface_id) => surface_id,
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
};
|
||||
let suffix_key_result = crate::upsert_launch_surface_key(
|
||||
self.database.as_ref(),
|
||||
&crate::KbLaunchSurfaceKeyDto::new(
|
||||
surface_id,
|
||||
"token_mint_suffix".to_string(),
|
||||
"moon".to_string(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = suffix_key_result {
|
||||
return Err(error);
|
||||
}
|
||||
Ok(surface_id)
|
||||
}
|
||||
|
||||
/// Ensures that the built-in `bags` launch surface exists and returns its id.
|
||||
pub async fn ensure_bags_surface(&self) -> Result<i64, crate::KbError> {
|
||||
let existing_result =
|
||||
crate::get_launch_surface_by_code(self.database.as_ref(), "bags").await;
|
||||
let existing_option = match existing_result {
|
||||
Ok(existing_option) => existing_option,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
match existing_option {
|
||||
Some(existing) => match existing.id {
|
||||
Some(surface_id) => Ok(surface_id),
|
||||
None => Err(crate::KbError::InvalidState(
|
||||
"bags launch surface has no internal id".to_string(),
|
||||
)),
|
||||
},
|
||||
None => {
|
||||
let dto = crate::KbLaunchSurfaceDto::new(
|
||||
"bags".to_string(),
|
||||
"Bags".to_string(),
|
||||
Some("launchpad".to_string()),
|
||||
true,
|
||||
);
|
||||
crate::upsert_launch_surface(self.database.as_ref(), &dto).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers one Bags pool mapping from the documented Bags API fields.
|
||||
pub async fn register_bags_pool_mapping(
|
||||
&self,
|
||||
token_mint: &str,
|
||||
dbc_config_key: std::option::Option<std::string::String>,
|
||||
dbc_pool_key: std::option::Option<std::string::String>,
|
||||
damm_v2_pool_key: std::option::Option<std::string::String>,
|
||||
) -> Result<i64, crate::KbError> {
|
||||
let surface_id_result = self.ensure_bags_surface().await;
|
||||
let surface_id = match surface_id_result {
|
||||
Ok(surface_id) => surface_id,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let token_key_result = crate::upsert_launch_surface_key(
|
||||
self.database.as_ref(),
|
||||
&crate::KbLaunchSurfaceKeyDto::new(
|
||||
surface_id,
|
||||
"token_mint".to_string(),
|
||||
token_mint.to_string(),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = token_key_result {
|
||||
return Err(error);
|
||||
}
|
||||
if let Some(dbc_config_key) = dbc_config_key {
|
||||
let key_result = crate::upsert_launch_surface_key(
|
||||
self.database.as_ref(),
|
||||
&crate::KbLaunchSurfaceKeyDto::new(
|
||||
surface_id,
|
||||
"config_account".to_string(),
|
||||
dbc_config_key,
|
||||
),
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = key_result {
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
if let Some(dbc_pool_key) = dbc_pool_key {
|
||||
let key_result = crate::upsert_launch_surface_key(
|
||||
self.database.as_ref(),
|
||||
&crate::KbLaunchSurfaceKeyDto::new(
|
||||
surface_id,
|
||||
"pool_account".to_string(),
|
||||
dbc_pool_key,
|
||||
),
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = key_result {
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
if let Some(damm_v2_pool_key) = damm_v2_pool_key {
|
||||
let key_result = crate::upsert_launch_surface_key(
|
||||
self.database.as_ref(),
|
||||
&crate::KbLaunchSurfaceKeyDto::new(
|
||||
surface_id,
|
||||
"pool_account".to_string(),
|
||||
damm_v2_pool_key,
|
||||
),
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = key_result {
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
Ok(surface_id)
|
||||
}
|
||||
|
||||
/// Attributes one transaction to known launch surfaces from decoded events.
|
||||
@@ -62,6 +209,10 @@ impl KbLaunchOriginService {
|
||||
)));
|
||||
}
|
||||
};
|
||||
let ensure_moonit_result = self.ensure_moonit_surface().await;
|
||||
if let Err(error) = ensure_moonit_result {
|
||||
return Err(error);
|
||||
}
|
||||
let decoded_events_result = crate::list_dex_decoded_events_by_transaction_id(
|
||||
self.database.as_ref(),
|
||||
transaction_id,
|
||||
@@ -73,9 +224,7 @@ impl KbLaunchOriginService {
|
||||
};
|
||||
let mut results = std::vec::Vec::new();
|
||||
for decoded_event in &decoded_events {
|
||||
let candidate_result = self
|
||||
.match_surface_for_decoded_event(decoded_event)
|
||||
.await;
|
||||
let candidate_result = self.match_surface_for_decoded_event(decoded_event).await;
|
||||
let candidate = match candidate_result {
|
||||
Ok(candidate) => candidate,
|
||||
Err(error) => return Err(error),
|
||||
@@ -188,10 +337,7 @@ impl KbLaunchOriginService {
|
||||
let signal_result = self
|
||||
.persistence
|
||||
.record_signal(&crate::KbDetectionSignalInput::new(
|
||||
format!(
|
||||
"signal.launch_surface.{}.detected",
|
||||
candidate.surface_code
|
||||
),
|
||||
format!("signal.launch_surface.{}.detected", candidate.surface_code),
|
||||
crate::KbAnalysisSignalSeverity::Low,
|
||||
transaction.signature.clone(),
|
||||
Some(observation_id),
|
||||
@@ -224,6 +370,15 @@ impl KbLaunchOriginService {
|
||||
if let Some(config_account) = decoded_event.market_account.clone() {
|
||||
candidates.push(("config_account".to_string(), config_account));
|
||||
}
|
||||
if let Some(pool_account) = decoded_event.pool_account.clone() {
|
||||
candidates.push(("pool_account".to_string(), pool_account));
|
||||
}
|
||||
if let Some(token_a_mint) = decoded_event.token_a_mint.clone() {
|
||||
candidates.push(("token_mint".to_string(), token_a_mint));
|
||||
}
|
||||
if let Some(token_b_mint) = decoded_event.token_b_mint.clone() {
|
||||
candidates.push(("token_mint".to_string(), token_b_mint));
|
||||
}
|
||||
let payload_result = serde_json::from_str::<serde_json::Value>(
|
||||
decoded_event.payload_json.as_str(),
|
||||
);
|
||||
@@ -234,13 +389,13 @@ impl KbLaunchOriginService {
|
||||
if let Some(payload) = payload.as_ref() {
|
||||
let creator = kb_extract_payload_string(
|
||||
payload,
|
||||
&["creator", "poolCreator", "user", "owner"],
|
||||
&["creator", "poolCreator", "user", "owner", "payer"],
|
||||
);
|
||||
if let Some(creator) = creator {
|
||||
candidates.push(("creator".to_string(), creator));
|
||||
}
|
||||
}
|
||||
for (match_kind, matched_value) in candidates {
|
||||
for (match_kind, matched_value) in &candidates {
|
||||
let key_result = crate::get_launch_surface_key_by_match(
|
||||
self.database.as_ref(),
|
||||
match_kind.as_str(),
|
||||
@@ -255,34 +410,109 @@ impl KbLaunchOriginService {
|
||||
Some(key) => key,
|
||||
None => continue,
|
||||
};
|
||||
let surface_id = key.launch_surface_id;
|
||||
let matched_result = self
|
||||
.build_matched_surface_from_key(
|
||||
key,
|
||||
match_kind.clone(),
|
||||
matched_value.clone(),
|
||||
)
|
||||
.await;
|
||||
let matched_option = match matched_result {
|
||||
Ok(matched_option) => matched_option,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
if matched_option.is_some() {
|
||||
return Ok(matched_option);
|
||||
}
|
||||
}
|
||||
let moonit_result = self.match_moonit_by_suffix(decoded_event).await;
|
||||
match moonit_result {
|
||||
Ok(moonit_result) => Ok(moonit_result),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
|
||||
async fn build_matched_surface_from_key(
|
||||
&self,
|
||||
key: crate::KbLaunchSurfaceKeyDto,
|
||||
match_kind: std::string::String,
|
||||
matched_value: std::string::String,
|
||||
) -> Result<std::option::Option<KbMatchedLaunchSurface>, crate::KbError> {
|
||||
let surface_result = crate::list_launch_surfaces(self.database.as_ref()).await;
|
||||
let surfaces = match surface_result {
|
||||
Ok(surfaces) => surfaces,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
for surface in surfaces {
|
||||
let surface_id_option = surface.id;
|
||||
let current_surface_id = match surface_id_option {
|
||||
let current_surface_id = match surface.id {
|
||||
Some(current_surface_id) => current_surface_id,
|
||||
None => continue,
|
||||
};
|
||||
if current_surface_id != surface_id || !surface.is_enabled {
|
||||
if current_surface_id != key.launch_surface_id || !surface.is_enabled {
|
||||
continue;
|
||||
}
|
||||
let matched_key_id = key.id;
|
||||
return Ok(Some(KbMatchedLaunchSurface {
|
||||
launch_surface_id: current_surface_id,
|
||||
matched_key_id,
|
||||
matched_key_id: key.id,
|
||||
surface_code: surface.code,
|
||||
surface_name: surface.name,
|
||||
match_kind,
|
||||
matched_value,
|
||||
}));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
async fn match_moonit_by_suffix(
|
||||
&self,
|
||||
decoded_event: &crate::KbDexDecodedEventDto,
|
||||
) -> Result<std::option::Option<KbMatchedLaunchSurface>, crate::KbError> {
|
||||
let mut token_mints = std::vec::Vec::new();
|
||||
if let Some(token_a_mint) = decoded_event.token_a_mint.clone() {
|
||||
token_mints.push(token_a_mint);
|
||||
}
|
||||
if let Some(token_b_mint) = decoded_event.token_b_mint.clone() {
|
||||
token_mints.push(token_b_mint);
|
||||
}
|
||||
let mut matched_token_option = None;
|
||||
for token_mint in token_mints {
|
||||
if token_mint.ends_with("moon") {
|
||||
matched_token_option = Some(token_mint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let matched_token = match matched_token_option {
|
||||
Some(matched_token) => matched_token,
|
||||
None => return Ok(None),
|
||||
};
|
||||
let surface_id_result = self.ensure_moonit_surface().await;
|
||||
let surface_id = match surface_id_result {
|
||||
Ok(surface_id) => surface_id,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let key_result = crate::get_launch_surface_key_by_match(
|
||||
self.database.as_ref(),
|
||||
"token_mint_suffix",
|
||||
"moon",
|
||||
)
|
||||
.await;
|
||||
let key_option = match key_result {
|
||||
Ok(key_option) => key_option,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let matched_key_id = match key_option {
|
||||
Some(key) => key.id,
|
||||
None => None,
|
||||
};
|
||||
Ok(Some(KbMatchedLaunchSurface {
|
||||
launch_surface_id: surface_id,
|
||||
matched_key_id,
|
||||
surface_code: "moonit".to_string(),
|
||||
surface_name: "Moonit".to_string(),
|
||||
match_kind: "token_mint_suffix".to_string(),
|
||||
matched_value: matched_token,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -357,9 +587,7 @@ mod tests {
|
||||
std::sync::Arc::new(database)
|
||||
}
|
||||
|
||||
async fn seed_fun_launch_registry(
|
||||
database: std::sync::Arc<crate::KbDatabase>,
|
||||
) {
|
||||
async fn seed_fun_launch_registry(database: std::sync::Arc<crate::KbDatabase>) {
|
||||
let surface_id_result = crate::upsert_launch_surface(
|
||||
database.as_ref(),
|
||||
&crate::KbLaunchSurfaceDto::new(
|
||||
@@ -469,8 +697,11 @@ mod tests {
|
||||
};
|
||||
assert_eq!(results.len(), 1);
|
||||
assert!(results[0].created_attribution);
|
||||
let list_result =
|
||||
crate::list_launch_attributions_by_pool_id(database.as_ref(), results[0].pool_id.unwrap()).await;
|
||||
let list_result = crate::list_launch_attributions_by_pool_id(
|
||||
database.as_ref(),
|
||||
results[0].pool_id.unwrap(),
|
||||
)
|
||||
.await;
|
||||
let listed = match list_result {
|
||||
Ok(listed) => listed,
|
||||
Err(error) => panic!("launch attribution list must succeed: {}", error),
|
||||
@@ -479,4 +710,171 @@ mod tests {
|
||||
assert_eq!(listed[0].match_kind, "config_account".to_string());
|
||||
assert_eq!(listed[0].matched_value, "DbcDetectConfig111".to_string());
|
||||
}
|
||||
|
||||
async fn seed_decoded_meteora_damm_v2_event_with_moon_token(
|
||||
database: std::sync::Arc<crate::KbDatabase>,
|
||||
signature: &str,
|
||||
) {
|
||||
let transaction_model = crate::KbTransactionModelService::new(database.clone());
|
||||
let dex_decode = crate::KbDexDecodeService::new(database.clone());
|
||||
let dex_detect = crate::KbDexDetectService::new(database);
|
||||
let resolved_transaction = serde_json::json!({
|
||||
"slot": 910105,
|
||||
"blockTime": 1779100105,
|
||||
"version": 0,
|
||||
"transaction": {
|
||||
"message": {
|
||||
"instructions": [
|
||||
{
|
||||
"programId": crate::KB_METEORA_DAMM_V2_PROGRAM_ID,
|
||||
"program": "meteora-damm-v2",
|
||||
"stackHeight": 1,
|
||||
"accounts": [
|
||||
"MoonitDammV2Pool111",
|
||||
"ExampleTokenmoon",
|
||||
"So11111111111111111111111111111111111111112",
|
||||
"MoonitDammV2Config111",
|
||||
"MoonitCreator111"
|
||||
],
|
||||
"parsed": {
|
||||
"info": {
|
||||
"instruction": "initialize_customizable_pool",
|
||||
"pool": "MoonitDammV2Pool111",
|
||||
"tokenAMint": "ExampleTokenmoon",
|
||||
"tokenBMint": "So11111111111111111111111111111111111111112",
|
||||
"creator": "MoonitCreator111",
|
||||
"isCustomizablePool": true
|
||||
}
|
||||
},
|
||||
"data": "opaque"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"err": null,
|
||||
"logMessages": [
|
||||
"Program log: Instruction: InitializeCustomizablePool"
|
||||
]
|
||||
}
|
||||
});
|
||||
let project_result = transaction_model
|
||||
.persist_resolved_transaction(
|
||||
signature,
|
||||
Some("helius_primary_http".to_string()),
|
||||
&resolved_transaction,
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = project_result {
|
||||
panic!("projection must succeed: {}", error);
|
||||
}
|
||||
let decode_result = dex_decode.decode_transaction_by_signature(signature).await;
|
||||
if let Err(error) = decode_result {
|
||||
panic!("dex decode must succeed: {}", error);
|
||||
}
|
||||
let detect_result = dex_detect.detect_transaction_by_signature(signature).await;
|
||||
if let Err(error) = detect_result {
|
||||
panic!("dex detect must succeed: {}", error);
|
||||
}
|
||||
}
|
||||
|
||||
async fn seed_bags_registry(
|
||||
database: std::sync::Arc<crate::KbDatabase>,
|
||||
) {
|
||||
let service = crate::KbLaunchOriginService::new(database);
|
||||
let register_result = service
|
||||
.register_bags_pool_mapping(
|
||||
"DbcDetectTokenA111",
|
||||
Some("DbcDetectConfig111".to_string()),
|
||||
Some("DbcDetectPool111".to_string()),
|
||||
Some("BagsMigratedPool111".to_string()),
|
||||
)
|
||||
.await;
|
||||
if let Err(error) = register_result {
|
||||
panic!("bags registry must succeed: {}", error);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn attribute_transaction_by_signature_detects_bags_from_registered_mapping() {
|
||||
let database = make_database().await;
|
||||
seed_bags_registry(database.clone()).await;
|
||||
seed_decoded_meteora_dbc_event(database.clone(), "sig-launch-origin-bags-1").await;
|
||||
let service = crate::KbLaunchOriginService::new(database.clone());
|
||||
let result = service
|
||||
.attribute_transaction_by_signature("sig-launch-origin-bags-1")
|
||||
.await;
|
||||
let results = match result {
|
||||
Ok(results) => results,
|
||||
Err(error) => panic!("bags attribution must succeed: {}", error),
|
||||
};
|
||||
assert_eq!(results.len(), 1);
|
||||
assert!(results[0].created_attribution);
|
||||
let surface_result =
|
||||
crate::get_launch_surface_by_code(database.as_ref(), "bags").await;
|
||||
let surface_option = match surface_result {
|
||||
Ok(surface_option) => surface_option,
|
||||
Err(error) => panic!("bags surface fetch must succeed: {}", error),
|
||||
};
|
||||
let surface = match surface_option {
|
||||
Some(surface) => surface,
|
||||
None => panic!("bags surface must exist"),
|
||||
};
|
||||
assert_eq!(surface.id, Some(results[0].launch_surface_id));
|
||||
let listed_result = crate::list_launch_attributions_by_pool_id(
|
||||
database.as_ref(),
|
||||
results[0].pool_id.unwrap(),
|
||||
)
|
||||
.await;
|
||||
let listed = match listed_result {
|
||||
Ok(listed) => listed,
|
||||
Err(error) => panic!("bags attribution list must succeed: {}", error),
|
||||
};
|
||||
assert_eq!(listed.len(), 1);
|
||||
assert_eq!(listed[0].match_kind, "config_account".to_string());
|
||||
assert_eq!(listed[0].matched_value, "DbcDetectConfig111".to_string());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn attribute_transaction_by_signature_detects_moonit_from_token_suffix() {
|
||||
let database = make_database().await;
|
||||
seed_decoded_meteora_damm_v2_event_with_moon_token(
|
||||
database.clone(),
|
||||
"sig-launch-origin-moonit-1",
|
||||
)
|
||||
.await;
|
||||
let service = crate::KbLaunchOriginService::new(database.clone());
|
||||
let result = service
|
||||
.attribute_transaction_by_signature("sig-launch-origin-moonit-1")
|
||||
.await;
|
||||
let results = match result {
|
||||
Ok(results) => results,
|
||||
Err(error) => panic!("moonit attribution must succeed: {}", error),
|
||||
};
|
||||
assert_eq!(results.len(), 1);
|
||||
assert!(results[0].created_attribution);
|
||||
let surface_result =
|
||||
crate::get_launch_surface_by_code(database.as_ref(), "moonit").await;
|
||||
let surface_option = match surface_result {
|
||||
Ok(surface_option) => surface_option,
|
||||
Err(error) => panic!("moonit surface fetch must succeed: {}", error),
|
||||
};
|
||||
let surface = match surface_option {
|
||||
Some(surface) => surface,
|
||||
None => panic!("moonit surface must exist"),
|
||||
};
|
||||
assert_eq!(surface.id, Some(results[0].launch_surface_id));
|
||||
let listed_result = crate::list_launch_attributions_by_pool_id(
|
||||
database.as_ref(),
|
||||
results[0].pool_id.unwrap(),
|
||||
)
|
||||
.await;
|
||||
let listed = match listed_result {
|
||||
Ok(listed) => listed,
|
||||
Err(error) => panic!("moonit attribution list must succeed: {}", error),
|
||||
};
|
||||
assert_eq!(listed.len(), 1);
|
||||
assert_eq!(listed[0].match_kind, "token_mint_suffix".to_string());
|
||||
assert_eq!(listed[0].matched_value, "ExampleTokenmoon".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user