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

Projected NFT indexing #158

Merged
merged 14 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from 10 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
1,151 changes: 740 additions & 411 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM rust:1.67 AS x-builder
FROM rust:1.73 AS x-builder

WORKDIR /indexer

Expand Down
7 changes: 3 additions & 4 deletions indexer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ strip = true

[dependencies]
# [core]
dcspark-core = { git = "https://github.com/dcSpark/dcspark-core.git", rev = "837b0135462ff7a1018942dca7198ad9c808a84c" }
dcspark-blockchain-source = { git = "https://github.com/dcSpark/dcspark-core.git", rev = "837b0135462ff7a1018942dca7198ad9c808a84c" }
multiverse = { git = "https://github.com/dcSpark/dcspark-core.git", rev = "837b0135462ff7a1018942dca7198ad9c808a84c" }
dcspark-core = { git = "https://github.com/dcSpark/dcspark-core.git", rev = "572af17e3e22101dee64e0999049a571aea26e0f" }
dcspark-blockchain-source = { git = "https://github.com/dcSpark/dcspark-core.git", rev = "572af17e3e22101dee64e0999049a571aea26e0f" }
multiverse = { git = "https://github.com/dcSpark/dcspark-core.git", rev = "572af17e3e22101dee64e0999049a571aea26e0f" }

# [local]
entity = { path = "entity" }
Expand All @@ -21,7 +21,6 @@ tasks = { path = "tasks" }
# [indexer]
anyhow = { version = "1.0.69" }
async-trait = { version = "0.1.64" }
base64 = { version = "0.21.0" }
cardano-multiplatform-lib = { git = "https://github.com/dcSpark/cardano-multiplatform-lib", branch = "metadata-and-addr" }
clap = { version = "3.1", features = ["derive"] }
ctrlc = { version = "3.2.4", features = ["termination"] }
Expand Down
1 change: 1 addition & 0 deletions indexer/entity/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ pub mod dex_swap;
pub mod native_asset;
pub mod plutus_data;
pub mod plutus_data_hash;
pub mod projected_nft;
pub mod stake_delegation;
pub mod transaction_metadata;
5 changes: 5 additions & 0 deletions indexer/entity/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ pub use super::plutus_data_hash::{
Entity as PlutusDataHash, Model as PlutusDataHashModel, PrimaryKey as PlutusDataHashPrimaryKey,
Relation as PlutusDataHashRelation,
};
pub use super::projected_nft::{
ActiveModel as ProjectedNftActiveModel, Column as ProjectedNftColumn, Entity as ProjectedNft,
Model as ProjectedNftModel, PrimaryKey as ProjectedNftPrimaryKey,
Relation as ProjectedNftRelation,
};
pub use super::stake_credential::{
ActiveModel as StakeCredentialActiveModel, Column as StakeCredentialColumn,
Entity as StakeCredential, Model as StakeCredentialModel,
Expand Down
55 changes: 55 additions & 0 deletions indexer/entity/src/projected_nft.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Deserialize, Serialize)]
#[sea_orm(table_name = "ProjectedNFT")]
pub struct Model {
#[sea_orm(primary_key, column_type = "BigInteger")]
pub id: i64,
pub owner_address: Vec<u8>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a Vec<u8> instead of a foreign key into the stake credential table (careful: there is no guarantee this staking key exists in the table)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a Vec<u8> instead of a foreign key into the stake credential table (careful: there is no guarantee this staking key exists in the table)

as soon as there's no guarantee and this address is what we actually get from the plutus datum i think it makes sense to leave it like this

pub previous_utxo_tx_hash: Vec<u8>,
#[sea_orm(column_type = "BigInteger", nullable)]
pub previous_utxo_tx_output_index: Option<i64>,
Comment on lines +10 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these not be a foreign key to the output table?

#[sea_orm(column_type = "BigInteger", nullable)]
pub hololocker_utxo_id: Option<i64>,
#[sea_orm(column_type = "BigInteger")]
pub tx_id: i64,
pub asset: String,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, we can use a foreign key for this asset as well

#[sea_orm(column_type = "BigInteger")]
pub amount: i64,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's too ugly, but you can probably get the amount information implicitly from the fact you're already referencing the UTXO table

pub operation: i32, // lock / unlock / claim
pub for_how_long: Option<i64>,
pub plutus_datum: Vec<u8>,
}

#[derive(Copy, Clone, Debug, DeriveRelation, EnumIter)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::transaction_output::Entity",
from = "Column::HololockerUtxoId",
to = "super::transaction_output::Column::Id"
)]
TransactionOutput,
#[sea_orm(
belongs_to = "super::transaction::Entity",
from = "Column::TxId",
to = "super::transaction::Column::Id"
)]
Transaction,
}

// TODO: figure out why this isn't automatically handle by the macros above
impl Related<super::transaction_output::Entity> for Entity {
fn to() -> RelationDef {
Relation::TransactionOutput.def()
}
}

// TODO: figure out why this isn't automatically handle by the macros above
impl Related<super::transaction::Entity> for Entity {
fn to() -> RelationDef {
Relation::Transaction.def()
}
}

impl ActiveModelBehavior for ActiveModel {}
2 changes: 2 additions & 0 deletions indexer/migration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod m20220808_000013_create_transaction_reference_input_table;
mod m20221031_000014_create_dex_table;
mod m20230223_000015_modify_block_table;
mod m20230927_000016_create_stake_delegation_table;
mod m20231025_000017_projected_nft;

pub struct Migrator;

Expand All @@ -43,6 +44,7 @@ impl MigratorTrait for Migrator {
Box::new(m20221031_000014_create_dex_table::Migration),
Box::new(m20230223_000015_modify_block_table::Migration),
Box::new(m20230927_000016_create_stake_delegation_table::Migration),
Box::new(m20231025_000017_projected_nft::Migration),
]
}
}
77 changes: 77 additions & 0 deletions indexer/migration/src/m20231025_000017_projected_nft.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use sea_schema::migration::prelude::*;

use entity::projected_nft::*;

pub struct Migration;

impl MigrationName for Migration {
fn name(&self) -> &str {
"m20231025_000016_projected_nft"
}
}

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Entity)
.if_not_exists()
.col(
ColumnDef::new(Column::Id)
.big_integer()
.not_null()
.auto_increment(),
)
.col(ColumnDef::new(Column::OwnerAddress).binary().not_null())
.col(
ColumnDef::new(Column::PreviousUtxoTxHash)
.binary()
.not_null(),
)
.col(ColumnDef::new(Column::PreviousUtxoTxOutputIndex).big_integer())
.col(ColumnDef::new(Column::HololockerUtxoId).big_integer())
.col(ColumnDef::new(Column::TxId).big_integer().not_null())
.col(ColumnDef::new(Column::Asset).text().not_null())
.col(ColumnDef::new(Column::Amount).big_integer().not_null())
.col(ColumnDef::new(Column::Operation).integer().not_null())
.col(ColumnDef::new(Column::PlutusDatum).binary().not_null())
.col(ColumnDef::new(Column::ForHowLong).big_integer())
.foreign_key(
ForeignKey::create()
.name("fk-projected_nft-tx_id")
.from(Entity, Column::TxId)
.to(
entity::prelude::Transaction,
entity::prelude::TransactionColumn::Id,
)
.on_delete(ForeignKeyAction::Cascade),
)
.foreign_key(
ForeignKey::create()
.name("fk-projected_nft-utxo_id")
.from(Entity, Column::HololockerUtxoId)
.to(
entity::prelude::TransactionOutput,
entity::prelude::TransactionOutputColumn::Id,
)
.on_delete(ForeignKeyAction::Cascade),
)
.primary_key(
Index::create()
.table(Entity)
.name("projected_nft-pk")
.col(Column::Id),
)
.to_owned(),
)
.await
}

async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Entity).to_owned())
.await
}
}
4 changes: 4 additions & 0 deletions indexer/tasks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ entity = { path = "../entity" }
# [tasks]
anyhow = { version = "1.0.69" }
cardano-multiplatform-lib = { git = "https://github.com/dcSpark/cardano-multiplatform-lib", branch = "metadata-and-addr" }
cml-chain = { git = "https://github.com/dcSpark/cardano-multiplatform-lib", rev = "acca172633d0570a7432058aa5b0717ad2f0c6d7" }
cml-core = { git = "https://github.com/dcSpark/cardano-multiplatform-lib", rev = "acca172633d0570a7432058aa5b0717ad2f0c6d7" }
cml-crypto = { git = "https://github.com/dcSpark/cardano-multiplatform-lib", rev = "acca172633d0570a7432058aa5b0717ad2f0c6d7" }
projected-nft-sdk = { git = "https://github.com/dcSpark/projected-nft-whirlpool.git", rev = "a350ccfcbdef22b73c93561c6816bd42b13f00ff" }
cfg-if = { version = "0.1.10" }
cryptoxide = { version = "0.4.2" }
hex = { version = "0.4.3" }
Expand Down
8 changes: 8 additions & 0 deletions indexer/tasks/src/config/AddressConfig.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use pallas::ledger::addresses::Address;
use pallas::ledger::primitives::alonzo::PlutusScript;
use pallas::ledger::primitives::babbage::PlutusV2Script;

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct PayloadAndReadonlyConfig {
pub address: String,
}
2 changes: 2 additions & 0 deletions indexer/tasks/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#[allow(non_snake_case)]
pub mod AddressConfig;
#[allow(non_snake_case)]
pub mod EmptyConfig;
#[allow(non_snake_case)]
pub mod PayloadAndReadonlyConfig;
Expand Down
2 changes: 1 addition & 1 deletion indexer/tasks/src/dsl/task_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ cfg_if::cfg_if! {
block,
handle,
perf_aggregator,
config: *config
config: config.clone(),
}
}

Expand Down
4 changes: 2 additions & 2 deletions indexer/tasks/src/multiera/dex/minswap_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Dex for MinSwapV1 {
&[POOL_SCRIPT_HASH1, POOL_SCRIPT_HASH2],
&tx.plutus_data(),
)
.get(0)
.first()
{
let datum = datum.to_json();

Expand Down Expand Up @@ -76,7 +76,7 @@ impl Dex for MinSwapV1 {
&[POOL_SCRIPT_HASH1, POOL_SCRIPT_HASH2],
&tx.plutus_data(),
)
.get(0)
.first()
{
let main_datum = main_datum.to_json();
let mut free_utxos: Vec<MultiEraOutput> = tx.outputs();
Expand Down
4 changes: 2 additions & 2 deletions indexer/tasks/src/multiera/dex/sundaeswap_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl Dex for SundaeSwapV1 {
// Note: there should be at most one pool output
if let Some((output, datum)) =
filter_outputs_and_datums_by_hash(&tx.outputs(), &[POOL_SCRIPT_HASH], &tx.plutus_data())
.get(0)
.first()
{
let datum = datum.to_json();

Expand Down Expand Up @@ -68,7 +68,7 @@ impl Dex for SundaeSwapV1 {
// Note: there should be at most one pool output
if let Some((main_output, main_datum)) =
filter_outputs_and_datums_by_hash(&tx.outputs(), &[POOL_SCRIPT_HASH], &tx.plutus_data())
.get(0)
.first()
{
let main_datum = main_datum.to_json();
let mut free_utxos: Vec<MultiEraOutput> = tx.outputs();
Expand Down
6 changes: 3 additions & 3 deletions indexer/tasks/src/multiera/dex/wingriders_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Dex for WingRidersV1 {
// Note: there should be at most one pool output
if let Some((output, datum)) =
filter_outputs_and_datums_by_hash(&tx.outputs(), &[POOL_SCRIPT_HASH], &tx.plutus_data())
.get(0)
.first()
{
let datum = datum.to_json();

Expand Down Expand Up @@ -81,12 +81,12 @@ impl Dex for WingRidersV1 {
// Note: there should be at most one pool output
if let Some((pool_output, _)) =
filter_outputs_and_datums_by_hash(&tx.outputs(), &[POOL_SCRIPT_HASH], &tx.plutus_data())
.get(0)
.first()
{
let redeemers = tx.redeemers().ok_or("No redeemers")?;

// Get pool input from redemeers
let pool_input_redeemer = redeemers.get(0).ok_or("No redeemers")?;
let pool_input_redeemer = redeemers.first().ok_or("No redeemers")?;
let pool_input = pool_input_redeemer.data.to_json()["fields"][0]["int"]
.as_i64()
.ok_or("Failed to parse pool input index")?;
Expand Down
1 change: 1 addition & 0 deletions indexer/tasks/src/multiera/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod multiera_executor;
pub mod multiera_metadata;
pub mod multiera_minswap_v1_mean_price;
pub mod multiera_minswap_v1_swap;
pub mod multiera_projected_nft;
pub mod multiera_reference_inputs;
pub mod multiera_stake_credentials;
pub mod multiera_sundaeswap_v1_mean_price;
Expand Down
Loading
Loading