ido: record created_at and launched_at timestamps
Add two timestamp columns to the ido table, both sourced from Delphi NFT commitments (48-bit LE unix seconds): - created_at (NOT NULL, default 0): from the Delphi NFT in the preinit's first output, set at IDO creation. 0 if the commitment is too short. - launched_at (NULL): from the Delphi NFT in output#3 of the launch transaction, set in lockstep with launch_txid. Null until launched. Both are threaded through the parse/context/update paths and exposed on IdoRpcRecord. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d5bdf5a740
commit
b8468a1256
1 changed files with 93 additions and 21 deletions
|
|
@ -708,7 +708,15 @@ pub async fn prepare_tables(pool: &SqlitePool) {
|
|||
txchain_entrypoint INTEGER NULL,
|
||||
txchain_head INTEGER NULL,
|
||||
is_valid INTEGER NOT NULL,
|
||||
is_token_created_at_preinit INTEGER NOT NULL
|
||||
is_token_created_at_preinit INTEGER NOT NULL,
|
||||
-- Unix timestamp (seconds) the IDO was created, taken from the
|
||||
-- Delphi NFT commitment in the preinit's first output. 0 if the
|
||||
-- commitment was too short to carry a timestamp.
|
||||
created_at INTEGER NOT NULL DEFAULT 0,
|
||||
-- Unix timestamp (seconds) the IDO was launched, taken from the
|
||||
-- Delphi NFT in output#3 of the launch transaction. NULL until the
|
||||
-- IDO is launched (launch_txid set).
|
||||
launched_at INTEGER NULL
|
||||
)",
|
||||
)
|
||||
.execute(pool)
|
||||
|
|
@ -799,6 +807,8 @@ pub struct IdoDBRecord {
|
|||
txchain_head: Option<i64>,
|
||||
is_valid: bool,
|
||||
is_token_created_at_preinit: bool,
|
||||
created_at: i64,
|
||||
launched_at: Option<i64>,
|
||||
}
|
||||
impl IdoDBRecord {
|
||||
fn from_row(row: &sqlx::sqlite::SqliteRow) -> Result<Self> {
|
||||
|
|
@ -817,6 +827,8 @@ impl IdoDBRecord {
|
|||
txchain_head: row.get(11),
|
||||
is_valid: row.get(12),
|
||||
is_token_created_at_preinit: row.get(13),
|
||||
created_at: row.get(14),
|
||||
launched_at: row.get(15),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -901,7 +913,7 @@ async fn ido_lookup(
|
|||
) -> Result<Option<IdoDBRecord>> {
|
||||
let row = sqlx::query(
|
||||
"SELECT internal_id, preinit_txid, init_txid, launch_txid, otoken_genesis_txid, offering_token_id, offered_token_id,
|
||||
status, parameters, state, txchain_entrypoint, txchain_head, is_valid, is_token_created_at_preinit
|
||||
status, parameters, state, txchain_entrypoint, txchain_head, is_valid, is_token_created_at_preinit, created_at, launched_at
|
||||
FROM ido WHERE internal_id = ?",
|
||||
)
|
||||
.bind(internal_id)
|
||||
|
|
@ -1042,12 +1054,17 @@ struct IdoContext {
|
|||
offered_token_id: Option<Vec<u8>>,
|
||||
offering_token_id: Option<Vec<u8>>,
|
||||
head_txid: Vec<u8>,
|
||||
created_at: i64,
|
||||
launched_at: Option<i64>,
|
||||
}
|
||||
|
||||
struct IdoPreinitParseParamsResult {
|
||||
preinit_parameters: IdoPreInitParameters,
|
||||
offered_token_is_in_supply: bool,
|
||||
is_valid_ido: bool,
|
||||
/// Creation time (unix seconds) from the Delphi NFT commitment in the
|
||||
/// preinit's first output; 0 if the commitment was too short to carry one.
|
||||
created_at: i64,
|
||||
}
|
||||
|
||||
fn parse_ido_preinit_tx_params(tx: &Transaction, delphi_token_id: &[u8], platform_fee_nfth: &[u8], errors: &mut Vec<Error>, invalid_ido_reasons: &mut Vec<Error>) -> Option<IdoPreinitParseParamsResult> {
|
||||
|
|
@ -1209,6 +1226,8 @@ fn parse_ido_preinit_tx_params(tx: &Transaction, delphi_token_id: &[u8], platfor
|
|||
// The first output must be the Delphi NFT. Its category must match the
|
||||
// announcement's delphiCategory, and the commitment timestamp (the current
|
||||
// time) must place launchConditions.expiresAt within the allowed offering window.
|
||||
// We also record the timestamp as the IDO's creation time.
|
||||
let mut created_at: i64 = 0;
|
||||
match tx.output.first() {
|
||||
Some(delphiOut) => match delphiOut.token.as_ref() {
|
||||
Some(delphiToken) if delphiToken.has_nft() => {
|
||||
|
|
@ -1224,6 +1243,7 @@ fn parse_ido_preinit_tx_params(tx: &Transaction, delphi_token_id: &[u8], platfor
|
|||
let c = &delphiToken.commitment;
|
||||
// 48-bit little-endian timestamp (see riftenlabs_defi::delphi::parse_delphi_update).
|
||||
let delphi_timestamp = u64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], 0, 0]);
|
||||
created_at = delphi_timestamp as i64;
|
||||
let offering_duration = &preinit_parameters.offering.launchConditions.expiresAt - BigInt::from(delphi_timestamp);
|
||||
if offering_duration < *MIN_OFFERING_DURATION {
|
||||
invalid_ido_reasons.push(anyhow::anyhow!("expiresAt - delphi timestamp < MIN_OFFERING_DURATION (1 day)"));
|
||||
|
|
@ -1250,6 +1270,7 @@ fn parse_ido_preinit_tx_params(tx: &Transaction, delphi_token_id: &[u8], platfor
|
|||
preinit_parameters,
|
||||
offered_token_is_in_supply,
|
||||
is_valid_ido,
|
||||
created_at,
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -1269,6 +1290,7 @@ struct IdoPreinitParseResult {
|
|||
is_valid_ido: bool,
|
||||
offered_token_is_in_supply: bool,
|
||||
offered_token_id: Option<Vec<u8>>,
|
||||
created_at: i64,
|
||||
}
|
||||
|
||||
fn parse_ido_preinit_tx(network: Option<Network>, tx: &Transaction, errors: &mut Vec<Error>, invalid_ido_reasons: &mut Vec<Error>) -> IdoPreinitParseResult {
|
||||
|
|
@ -1285,17 +1307,20 @@ fn parse_ido_preinit_tx(network: Option<Network>, tx: &Transaction, errors: &mut
|
|||
let offered_token_is_in_supply: bool;
|
||||
let mut is_valid_ido: bool;
|
||||
let nullable_preinit_parameters: Option<IdoPreInitParameters>;
|
||||
let created_at: i64;
|
||||
// preinit announcement
|
||||
match parse_ido_preinit_tx_params(tx, &delphi_token_id, &platform_fee_nfth, errors, invalid_ido_reasons) {
|
||||
Some(output) => {
|
||||
offered_token_is_in_supply = output.offered_token_is_in_supply;
|
||||
is_valid_ido = output.is_valid_ido;
|
||||
nullable_preinit_parameters = Some(output.preinit_parameters);
|
||||
created_at = output.created_at;
|
||||
}
|
||||
None => {
|
||||
offered_token_is_in_supply = false;
|
||||
is_valid_ido = false;
|
||||
nullable_preinit_parameters = None;
|
||||
created_at = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1526,6 +1551,7 @@ fn parse_ido_preinit_tx(network: Option<Network>, tx: &Transaction, errors: &mut
|
|||
is_valid_ido,
|
||||
offered_token_is_in_supply,
|
||||
offered_token_id,
|
||||
created_at,
|
||||
}
|
||||
} else {
|
||||
IdoPreinitParseResult {
|
||||
|
|
@ -1534,6 +1560,7 @@ fn parse_ido_preinit_tx(network: Option<Network>, tx: &Transaction, errors: &mut
|
|||
is_valid_ido,
|
||||
offered_token_is_in_supply: false,
|
||||
offered_token_id: None,
|
||||
created_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1558,6 +1585,8 @@ fn create_ido_context_from_preinit(network: Option<Network>, tx: &Transaction, e
|
|||
offering_token_id: None,
|
||||
is_token_created_at_preinit: !result.offered_token_is_in_supply,
|
||||
head_txid: tx.compute_txid().to_blob(),
|
||||
created_at: result.created_at,
|
||||
launched_at: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1589,8 +1618,8 @@ async fn on_create_ido(
|
|||
// create the ido
|
||||
let mut dbtx = pool.begin().await?;
|
||||
let result = sqlx::query(
|
||||
"INSERT INTO ido (preinit_txid, init_txid, launch_txid, otoken_genesis_txid, offering_token_id, offered_token_id, status, parameters, state, is_valid, is_token_created_at_preinit, txchain_entrypoint, txchain_head)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
"INSERT INTO ido (preinit_txid, init_txid, launch_txid, otoken_genesis_txid, offering_token_id, offered_token_id, status, parameters, state, is_valid, is_token_created_at_preinit, created_at, launched_at, txchain_entrypoint, txchain_head)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
)
|
||||
.bind(context.preinit_txid)
|
||||
.bind(context.init_txid)
|
||||
|
|
@ -1603,6 +1632,8 @@ async fn on_create_ido(
|
|||
.bind(serde_json::to_vec(&context.state).unwrap())
|
||||
.bind(context.is_valid_ido)
|
||||
.bind(context.is_token_created_at_preinit)
|
||||
.bind(context.created_at)
|
||||
.bind(context.launched_at)
|
||||
.bind(None::<i64>)
|
||||
.bind(None::<i64>)
|
||||
.execute(&mut *dbtx)
|
||||
|
|
@ -1655,7 +1686,10 @@ struct IdoUpdateEntry {
|
|||
#[derive(Clone)]
|
||||
enum IdoUpdate {
|
||||
InitTxId(Vec<u8>),
|
||||
LaunchTxId(Vec<u8>),
|
||||
LaunchTxId {
|
||||
txid: Vec<u8>,
|
||||
launched_at: Option<i64>,
|
||||
},
|
||||
OTokenGenesisTxId(Vec<u8>),
|
||||
Status(String),
|
||||
State(IdoState),
|
||||
|
|
@ -1677,6 +1711,26 @@ fn rev_blob(v: &[u8]) -> Vec<u8> {
|
|||
v.iter().copied().rev().collect()
|
||||
}
|
||||
|
||||
/// Read the 48-bit little-endian unix timestamp (seconds) carried in the first
|
||||
/// 6 bytes of a Delphi NFT commitment. Returns None if the commitment is too
|
||||
/// short to contain one. (see riftenlabs_defi::delphi::parse_delphi_update)
|
||||
fn delphi_commitment_timestamp(commitment: &[u8]) -> Option<i64> {
|
||||
if commitment.len() < 6 {
|
||||
return None;
|
||||
}
|
||||
let c = commitment;
|
||||
Some(u64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], 0, 0]) as i64)
|
||||
}
|
||||
|
||||
/// Read `launched_at` (unix seconds) from the Delphi NFT in output#3 of a launch
|
||||
/// transaction. Returns None if the output, its token, or its timestamp is absent.
|
||||
fn launch_tx_launched_at(tx: &Transaction) -> Option<i64> {
|
||||
tx.output
|
||||
.get(3)
|
||||
.and_then(|o| o.token.as_ref())
|
||||
.and_then(|t| delphi_commitment_timestamp(&t.commitment))
|
||||
}
|
||||
|
||||
fn print_updates(updates: &[IdoUpdate]) -> () {
|
||||
for update in updates {
|
||||
match update {
|
||||
|
|
@ -1684,7 +1738,7 @@ fn print_updates(updates: &[IdoUpdate]) -> () {
|
|||
let v=rev_blob(txid);
|
||||
debug!("IDO IdoUpdate::InitTxId(txid): {}", hex::encode(v));
|
||||
},
|
||||
IdoUpdate::LaunchTxId(txid) => {
|
||||
IdoUpdate::LaunchTxId { txid, .. } => {
|
||||
let v=rev_blob(txid);
|
||||
debug!("IDO IdoUpdate::LaunchTxId(txid): {}", hex::encode(v));
|
||||
},
|
||||
|
|
@ -1882,7 +1936,10 @@ fn ido_add_tx(
|
|||
return Err(anyhow::anyhow!("Incorrect commitment size at output#0"));
|
||||
}
|
||||
updates.push(IdoUpdate::Status("DISTRIBUTING".to_string()));
|
||||
updates.push(IdoUpdate::LaunchTxId(tx.compute_txid().to_blob()));
|
||||
updates.push(IdoUpdate::LaunchTxId {
|
||||
txid: tx.compute_txid().to_blob(),
|
||||
launched_at: launch_tx_launched_at(tx),
|
||||
});
|
||||
updates.push(IdoUpdate::State(
|
||||
IdoState::Distributing(IdoDistributingState {
|
||||
authguardCategory: active_state.authguardCategory.clone(),
|
||||
|
|
@ -1904,7 +1961,10 @@ fn ido_add_tx(
|
|||
return Err(anyhow::anyhow!("Incorrect commitment size at output#0"));
|
||||
}
|
||||
updates.push(IdoUpdate::Status("POSTLAUNCH".to_string()));
|
||||
updates.push(IdoUpdate::LaunchTxId(tx.compute_txid().to_blob()));
|
||||
updates.push(IdoUpdate::LaunchTxId {
|
||||
txid: tx.compute_txid().to_blob(),
|
||||
launched_at: launch_tx_launched_at(tx),
|
||||
});
|
||||
updates.push(IdoUpdate::State(
|
||||
IdoState::PostLaunch(IdoPostLaunchState {
|
||||
authguardCategory: active_state.authguardCategory.clone(),
|
||||
|
|
@ -2057,7 +2117,7 @@ async fn update_ido(
|
|||
) -> Result<()> {
|
||||
sqlx::query(
|
||||
"UPDATE ido set init_txid = ?, launch_txid = ?, otoken_genesis_txid = ?, status = ?, parameters = ?, state = ?,
|
||||
offering_token_id = ?, offered_token_id = ?, txchain_head = ?, is_valid = ? WHERE internal_id = ?",
|
||||
offering_token_id = ?, offered_token_id = ?, txchain_head = ?, is_valid = ?, launched_at = ? WHERE internal_id = ?",
|
||||
)
|
||||
.bind(&context.init_txid)
|
||||
.bind(&context.launch_txid)
|
||||
|
|
@ -2069,6 +2129,7 @@ async fn update_ido(
|
|||
.bind(&context.offered_token_id)
|
||||
.bind(txchain_head)
|
||||
.bind(context.is_valid_ido)
|
||||
.bind(context.launched_at)
|
||||
.bind(internal_id)
|
||||
.execute(&mut **dbtx)
|
||||
.await?;
|
||||
|
|
@ -2084,8 +2145,9 @@ fn apply_updates_to_context(
|
|||
IdoUpdate::InitTxId(txid) => {
|
||||
context.init_txid = Some(txid.clone());
|
||||
},
|
||||
IdoUpdate::LaunchTxId(txid) => {
|
||||
IdoUpdate::LaunchTxId { txid, launched_at } => {
|
||||
context.launch_txid = Some(txid.clone());
|
||||
context.launched_at = *launched_at;
|
||||
},
|
||||
IdoUpdate::OTokenGenesisTxId(txid) => {
|
||||
context.otoken_genesis_txid = Some(txid.clone());
|
||||
|
|
@ -2306,6 +2368,8 @@ async fn on_add_ido_tx(
|
|||
offered_token_id: ido.offered_token_id.clone(),
|
||||
offering_token_id: ido.offering_token_id.clone(),
|
||||
head_txid: prev_txchain_item.txid.clone(),
|
||||
created_at: ido.created_at,
|
||||
launched_at: ido.launched_at,
|
||||
};
|
||||
// add to the chain
|
||||
let result = ido_add_tx(&context, tx)?;
|
||||
|
|
@ -2449,6 +2513,12 @@ pub struct IdoRpcRecord {
|
|||
/// Txid (display hex) of the txchain head record, or null if there is no head.
|
||||
pub txchain_head: Option<String>,
|
||||
pub is_valid: bool,
|
||||
/// Unix timestamp (seconds) the IDO was created, from the preinit's Delphi
|
||||
/// NFT commitment; 0 if unavailable.
|
||||
pub created_at: i64,
|
||||
/// Unix timestamp (seconds) the IDO was launched, from the Delphi NFT in
|
||||
/// output#3 of the launch transaction; null until launched.
|
||||
pub launched_at: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
|
|
@ -2500,6 +2570,8 @@ impl IdoDBRecord {
|
|||
state: serde_json::from_slice(&self.state)?,
|
||||
txchain_head: txchain_head_txid.as_deref().map(blob_to_display_hex::<Txid>).transpose()?,
|
||||
is_valid: self.is_valid,
|
||||
created_at: self.created_at,
|
||||
launched_at: self.launched_at,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -2591,7 +2663,7 @@ pub async fn list_idos(
|
|||
let mut qb: sqlx::QueryBuilder<sqlx::Sqlite> = sqlx::QueryBuilder::new(
|
||||
"SELECT ido.internal_id, ido.preinit_txid, ido.init_txid, ido.launch_txid, ido.otoken_genesis_txid, \
|
||||
ido.offering_token_id, ido.offered_token_id, \
|
||||
ido.status, ido.parameters, ido.state, ido.txchain_entrypoint, ido.txchain_head, ido.is_valid, ido.is_token_created_at_preinit, \
|
||||
ido.status, ido.parameters, ido.state, ido.txchain_entrypoint, ido.txchain_head, ido.is_valid, ido.is_token_created_at_preinit, ido.created_at, ido.launched_at, \
|
||||
head_tx.txid \
|
||||
FROM ido LEFT JOIN ido_txchain head_tx ON head_tx.id = ido.txchain_head WHERE 1=1",
|
||||
);
|
||||
|
|
@ -2617,7 +2689,7 @@ pub async fn list_idos(
|
|||
.await?
|
||||
.into_iter()
|
||||
.map(|row| {
|
||||
let txchain_head_txid: Option<Vec<u8>> = row.get(14);
|
||||
let txchain_head_txid: Option<Vec<u8>> = row.get(16);
|
||||
IdoDBRecord::from_row(&row)?.into_rpc_record(txchain_head_txid)
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -2629,7 +2701,7 @@ pub async fn get_ido_by_preinit_txid(
|
|||
) -> Result<Option<IdoRpcRecord>> {
|
||||
let row = sqlx::query(
|
||||
"SELECT ido.internal_id, ido.preinit_txid, ido.init_txid, ido.launch_txid, ido.otoken_genesis_txid, ido.offering_token_id, ido.offered_token_id, \
|
||||
ido.status, ido.parameters, ido.state, ido.txchain_entrypoint, ido.txchain_head, ido.is_valid, ido.is_token_created_at_preinit, \
|
||||
ido.status, ido.parameters, ido.state, ido.txchain_entrypoint, ido.txchain_head, ido.is_valid, ido.is_token_created_at_preinit, ido.created_at, ido.launched_at, \
|
||||
head_tx.txid \
|
||||
FROM ido LEFT JOIN ido_txchain head_tx ON head_tx.id = ido.txchain_head WHERE ido.preinit_txid = ?",
|
||||
)
|
||||
|
|
@ -2637,7 +2709,7 @@ pub async fn get_ido_by_preinit_txid(
|
|||
.fetch_optional(pool)
|
||||
.await?;
|
||||
row.map(|r| {
|
||||
let txchain_head_txid: Option<Vec<u8>> = r.get(14);
|
||||
let txchain_head_txid: Option<Vec<u8>> = r.get(16);
|
||||
IdoDBRecord::from_row(&r)?.into_rpc_record(txchain_head_txid)
|
||||
})
|
||||
.transpose()
|
||||
|
|
@ -2649,7 +2721,7 @@ pub async fn get_ido_by_offering_token_id(
|
|||
) -> Result<Option<IdoRpcRecord>> {
|
||||
let row = sqlx::query(
|
||||
"SELECT ido.internal_id, ido.preinit_txid, ido.init_txid, ido.launch_txid, ido.otoken_genesis_txid, ido.offering_token_id, ido.offered_token_id, \
|
||||
ido.status, ido.parameters, ido.state, ido.txchain_entrypoint, ido.txchain_head, ido.is_valid, ido.is_token_created_at_preinit, \
|
||||
ido.status, ido.parameters, ido.state, ido.txchain_entrypoint, ido.txchain_head, ido.is_valid, ido.is_token_created_at_preinit, ido.created_at, ido.launched_at, \
|
||||
head_tx.txid \
|
||||
FROM ido LEFT JOIN ido_txchain head_tx ON head_tx.id = ido.txchain_head WHERE ido.offering_token_id = ?",
|
||||
)
|
||||
|
|
@ -2657,7 +2729,7 @@ pub async fn get_ido_by_offering_token_id(
|
|||
.fetch_optional(pool)
|
||||
.await?;
|
||||
row.map(|r| {
|
||||
let txchain_head_txid: Option<Vec<u8>> = r.get(14);
|
||||
let txchain_head_txid: Option<Vec<u8>> = r.get(16);
|
||||
IdoDBRecord::from_row(&r)?.into_rpc_record(txchain_head_txid)
|
||||
})
|
||||
.transpose()
|
||||
|
|
@ -3157,7 +3229,7 @@ mod querytests {
|
|||
let preinit_hex = hex::encode(txid(1));
|
||||
insert_test_entry(&pool, ido_id, txid(10), false).await;
|
||||
insert_test_entry(&pool, ido_id, txid(11), true).await;
|
||||
let all = list_ido_entries(&pool, ido_id, &preinit_hex, None, 0, 100).await.unwrap();
|
||||
let all = list_ido_entries(&pool, ido_id, &preinit_hex, None, &[], 0, 100).await.unwrap();
|
||||
assert_eq!(all.len(), 2);
|
||||
}
|
||||
|
||||
|
|
@ -3169,10 +3241,10 @@ mod querytests {
|
|||
insert_test_entry(&pool, ido_id, txid(10), false).await;
|
||||
insert_test_entry(&pool, ido_id, txid(11), true).await;
|
||||
insert_test_entry(&pool, ido_id, txid(12), true).await;
|
||||
let dist = list_ido_entries(&pool, ido_id, &preinit_hex, Some(true), 0, 100).await.unwrap();
|
||||
let dist = list_ido_entries(&pool, ido_id, &preinit_hex, Some(true), &[], 0, 100).await.unwrap();
|
||||
assert_eq!(dist.len(), 2);
|
||||
assert!(dist.iter().all(|e| e.distributed));
|
||||
let undist = list_ido_entries(&pool, ido_id, &preinit_hex, Some(false), 0, 100).await.unwrap();
|
||||
let undist = list_ido_entries(&pool, ido_id, &preinit_hex, Some(false), &[], 0, 100).await.unwrap();
|
||||
assert_eq!(undist.len(), 1);
|
||||
assert!(!undist[0].distributed);
|
||||
}
|
||||
|
|
@ -3187,8 +3259,8 @@ mod querytests {
|
|||
insert_test_entry(&pool, ido1, txid(10), false).await;
|
||||
insert_test_entry(&pool, ido1, txid(11), false).await;
|
||||
insert_test_entry(&pool, ido2, txid(12), false).await;
|
||||
let e1 = list_ido_entries(&pool, ido1, &preinit_hex_1, None, 0, 100).await.unwrap();
|
||||
let e2 = list_ido_entries(&pool, ido2, &preinit_hex_2, None, 0, 100).await.unwrap();
|
||||
let e1 = list_ido_entries(&pool, ido1, &preinit_hex_1, None, &[], 0, 100).await.unwrap();
|
||||
let e2 = list_ido_entries(&pool, ido2, &preinit_hex_2, None, &[], 0, 100).await.unwrap();
|
||||
assert_eq!(e1.len(), 2);
|
||||
assert_eq!(e2.len(), 1);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue