diff --git a/Cargo.lock b/Cargo.lock index 92e4659..3130243 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,7 +22,7 @@ dependencies = [ [[package]] name = "antelope_tokens" -version = "0.3.8" +version = "0.4.0" dependencies = [ "antelope", "prost 0.11.9", diff --git a/Cargo.toml b/Cargo.toml index b29db09..13c6a7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "antelope_tokens" -version = "0.3.8" +version = "0.4.0" authors = [ "Denis ", "Yaro ", diff --git a/README.md b/README.md index f27009e..9d59056 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ $ make gui ```mermaid graph TD; - map_transfers[map: map_transfers]; - sf.antelope.type.v1.Block[source: sf.antelope.type.v1.Block] --> map_transfers; + map_events[map: map_events]; + sf.antelope.type.v1.Block[source: sf.antelope.type.v1.Block] --> map_events; map_accounts[map: map_accounts]; sf.antelope.type.v1.Block[source: sf.antelope.type.v1.Block] --> map_accounts; map_stat[map: map_stat]; @@ -25,75 +25,75 @@ graph TD; graph_out[map: graph_out]; map_accounts --> graph_out; map_stat --> graph_out; - map_transfers --> graph_out; + map_events --> graph_out; ch_out[map: ch_out]; map_accounts --> ch_out; map_stat --> ch_out; - map_transfers --> ch_out; + map_events --> ch_out; ``` ### Modules ```yaml Package name: antelope_tokens -Version: v0.3.8 +Version: v0.4.0 Doc: Antelope `eosio.token` based action traces & database operations. Modules: - ---- -Name: map_transfers +---- +Name: map_events Initial block: 0 Kind: map Input: source: sf.antelope.type.v1.Block -Output Type: proto:antelope.eosio.token.v1.TransferEvents -Hash: 68580bd87f70567d5a794b7ed2c42829563c17a6 +Output Type: proto:antelope.eosio.token.v1.Events +Hash: c85c7f8fad2a0d03984c00ee15d1ded54bfa700e Name: map_accounts Initial block: 0 Kind: map Input: source: sf.antelope.type.v1.Block Output Type: proto:antelope.eosio.token.v1.Accounts -Hash: dc10dd69bc5bc0ae08a87724995a97e728158dbd +Hash: e85688fa74de76ee66c793b77190025baa242b4a Name: map_stat Initial block: 0 Kind: map Input: source: sf.antelope.type.v1.Block Output Type: proto:antelope.eosio.token.v1.Stats -Hash: 8124e7464c489fe27ee13e4f1ed80abb4c8b6763 +Hash: c3ba86b0f3f4fdb79e7e51d82fc114df45abc4f9 Name: graph_out Initial block: 0 Kind: map Input: map: map_accounts Input: map: map_stat -Input: map: map_transfers +Input: map: map_events Output Type: proto:sf.substreams.sink.entity.v1.EntityChanges -Hash: d4b1a6dc23e5467da5e613ed76366cd73a43fade +Hash: 64faa1889da48de19fea8d3b68595f844bba32e9 Name: ch_out Initial block: 0 Kind: map Input: map: map_accounts Input: map: map_stat -Input: map: map_transfers +Input: map: map_events Output Type: proto:sf.substreams.sink.database.v1.DatabaseChanges -Hash: 6f3621429ae1087b55ba3753a1d0cd7cb632948d +Hash: f4573a7e43387bde4d3572bb649dc315e64f3913 Sink config: - ---- +---- type: sf.substreams.sink.sql.v1.Service configs: - - schema: (6376 bytes) MD5SUM: 6c54c43f4c19f465e51cf36c415bc9f6 [LOADED_FILE] - - dbt_config: - - files: (empty) [ZIPPED_FOLDER] - - run_interval_seconds: 0 - - enabled: false - - wire_protocol_access: false - - hasura_frontend: - - enabled: false - - postgraphile_frontend: - - enabled: false - - pgweb_frontend: - - enabled: false - - engine: 2 +- schema: (6814 bytes) MD5SUM: adf98a1becc37604e5f14ce2ed6a1629 [LOADED_FILE] +- dbt_config: + - files: (empty) [ZIPPED_FOLDER] + - run_interval_seconds: 0 + - enabled: false +- wire_protocol_access: false +- hasura_frontend: + - enabled: false +- postgraphile_frontend: + - enabled: false +- pgweb_frontend: + - enabled: false +- engine: 2 ``` diff --git a/proto/v1/eosio.token.proto b/proto/v1/eosio.token.proto index a188ef5..e64fea8 100644 --- a/proto/v1/eosio.token.proto +++ b/proto/v1/eosio.token.proto @@ -5,7 +5,7 @@ package antelope.eosio.token.v1; import "google/protobuf/timestamp.proto"; message Accounts { - repeated Account items = 1; + repeated Account changes = 1; } message Account { @@ -33,7 +33,7 @@ message Account { } message Stats { - repeated Stat items = 1; + repeated Stat changes = 1; } message Stat { @@ -61,18 +61,20 @@ message Stat { google.protobuf.Timestamp timestamp = 14; } -message TransferEvents { - repeated TransferEvent items = 1; +message Events { + repeated Transfer transfers = 1; + repeated Issue issues = 2; + repeated Retire retires = 3; + repeated Create creates = 4; } -message TransferEvent { +message Transfer { // trace information string trx_id = 1; uint32 action_index = 2; // contract & scope string contract = 3; - string action = 4; string symcode = 5; // data payload @@ -90,3 +92,75 @@ message TransferEvent { uint64 block_num = 13; google.protobuf.Timestamp timestamp = 14; } + +message Issue { + // trace information + string trx_id = 1; + uint32 action_index = 2; + + // contract & scope + string contract = 3; + string symcode = 4; + + // data payload + string issuer = 5; + string to = 6; + string quantity = 7; + string memo = 8; + + // extras + uint32 precision = 9; + int64 amount = 10; + double value = 11; + + // block information + uint64 block_num = 12; + google.protobuf.Timestamp timestamp = 13; +} + +message Retire { + // trace information + string trx_id = 1; + uint32 action_index = 2; + + // contract & scope + string contract = 3; + string symcode = 5; + + // data payload + string from = 6; + string quantity = 7; + string memo = 8; + + // extras + uint32 precision = 9; + int64 amount = 10; + double value = 11; + + // block information + uint64 block_num = 12; + google.protobuf.Timestamp timestamp = 13; +} + +message Create { + // trace information + string trx_id = 1; + uint32 action_index = 2; + + // contract & scope + string contract = 3; + string symcode = 5; + + // data payload + string issuer = 6; + string maximum_supply = 7; + + // extras + uint32 precision = 8; + int64 amount = 9; + double value = 10; + + // block information + uint64 block_num = 11; + google.protobuf.Timestamp timestamp = 12; +} \ No newline at end of file diff --git a/src/maps.rs b/src/maps.rs index 6495a80..82e8cba 100644 --- a/src/maps.rs +++ b/src/maps.rs @@ -10,7 +10,7 @@ use crate::utils; #[substreams::handlers::map] fn map_accounts(block: Block) -> Result { - let items = block.transaction_traces().flat_map(|trx| { + let changes = block.transaction_traces().flat_map(|trx| { trx.db_ops.iter().filter_map(|db_op| { if db_op.table_name != "accounts" { return None; @@ -70,12 +70,12 @@ fn map_accounts(block: Block) -> Result { }) }).collect(); - Ok(Accounts { items }) + Ok(Accounts { changes }) } #[substreams::handlers::map] fn map_stat(block: Block) -> Result { - let items = block.transaction_traces().flat_map(|trx| { + let changes = block.transaction_traces().flat_map(|trx| { trx.db_ops.iter().filter_map(|db_op| { if db_op.table_name != "stat" { return None; @@ -147,13 +147,13 @@ fn map_stat(block: Block) -> Result { }) .collect(); - Ok(Stats { items }) + Ok(Stats { changes }) } #[substreams::handlers::map] -fn map_transfers(block: Block) -> Result { +fn map_events(block: Block) -> Result { - let items = block.actions::(&[]).filter_map(|(action, action_trace, trx)| { + let transfers = block.actions::(&[]).filter_map(|(action, action_trace, trx)| { let quantity = match action.quantity.parse::() { Ok(asset) => asset, @@ -162,25 +162,21 @@ fn map_transfers(block: Block) -> Result { return None; } }; - let symcode = quantity.symbol.code().to_string(); - let precision = quantity.symbol.precision().into(); - let amount = quantity.amount; - Some(TransferEvent { + Some(Transfer { trx_id: trx.id.clone(), action_index: action_trace.action_ordinal, contract: action_trace.action.as_ref().unwrap().account.clone(), - action: action_trace.action.as_ref().unwrap().name.clone(), - symcode, + symcode: quantity.symbol.code().to_string(), from: action.from, to: action.to, quantity: action.quantity, memo: action.memo, - precision, - amount, + precision: quantity.symbol.precision().into(), + amount: quantity.amount, value: utils::to_value(&quantity), block_num: block.number as u64, @@ -189,5 +185,100 @@ fn map_transfers(block: Block) -> Result { }) .collect(); - Ok(TransferEvents { items }) + let issues = block.actions::(&[]).filter_map(|(action, action_trace, trx)| { + + let quantity = match action.quantity.parse::() { + Ok(asset) => asset, + Err(e) => { + log::info!("Error parsing issue asset in trx {}: {:?}", trx.id, e); + return None; + } + }; + + Some(Issue { + trx_id: trx.id.clone(), + action_index: action_trace.action_ordinal, + + contract: action_trace.action.as_ref().unwrap().account.clone(), + symcode: quantity.symbol.code().to_string(), + + issuer: action_trace.receiver.clone(), + to: action.to, + quantity: action.quantity, + memo: action.memo, + + precision: quantity.symbol.precision().into(), + amount: quantity.amount, + value: utils::to_value(&quantity), + + block_num: block.number as u64, + timestamp: block.header.as_ref().unwrap().timestamp.clone(), + }) + }) + .collect(); + + let retires = block.actions::(&[]).filter_map(|(action, action_trace, trx)| { + + let quantity = match action.quantity.parse::() { + Ok(asset) => asset, + Err(e) => { + log::info!("Error parsing retire asset in trx {}: {:?}", trx.id, e); + return None; + } + }; + + Some(Retire { + trx_id: trx.id.clone(), + action_index: action_trace.action_ordinal, + + contract: action_trace.action.as_ref().unwrap().account.clone(), + symcode: quantity.symbol.code().to_string(), + + from: action_trace.receiver.clone(), + quantity: action.quantity, + memo: action.memo, + + precision: quantity.symbol.precision().into(), + amount: quantity.amount, + value: utils::to_value(&quantity), + + block_num: block.number as u64, + timestamp: block.header.as_ref().unwrap().timestamp.clone(), + }) + }) + .collect(); + + let creates = block.actions::(&[]).filter_map(|(action, action_trace, trx)| { + + let maximum_supply = match action.maximum_supply.parse::() { + Ok(asset) => asset, + Err(e) => { + log::info!("Error parsing create max supply asset in trx {}: {:?}", trx.id, e); + return None; + } + }; + + Some(Create { + trx_id: trx.id.clone(), + action_index: action_trace.action_ordinal, + + contract: action_trace.action.as_ref().unwrap().account.clone(), + symcode: maximum_supply.symbol.code().to_string(), + + issuer: action_trace.receiver.clone(), + maximum_supply: action.maximum_supply, + + precision: maximum_supply.symbol.precision().into(), + amount: maximum_supply.amount, + value: utils::to_value(&maximum_supply), + + block_num: block.number as u64, + timestamp: block.header.as_ref().unwrap().timestamp.clone(), + }) + }) + .collect(); + + + + Ok(Events { transfers, issues, retires, creates }) } diff --git a/src/pb/antelope.eosio.token.v1.rs b/src/pb/antelope.eosio.token.v1.rs index bc09ac4..96ce449 100644 --- a/src/pb/antelope.eosio.token.v1.rs +++ b/src/pb/antelope.eosio.token.v1.rs @@ -3,7 +3,7 @@ #[derive(Clone, PartialEq, ::prost::Message)] pub struct Accounts { #[prost(message, repeated, tag="1")] - pub items: ::prost::alloc::vec::Vec, + pub changes: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -42,7 +42,7 @@ pub struct Account { #[derive(Clone, PartialEq, ::prost::Message)] pub struct Stats { #[prost(message, repeated, tag="1")] - pub items: ::prost::alloc::vec::Vec, + pub changes: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -81,13 +81,19 @@ pub struct Stat { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransferEvents { +pub struct Events { #[prost(message, repeated, tag="1")] - pub items: ::prost::alloc::vec::Vec, + pub transfers: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="2")] + pub issues: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="3")] + pub retires: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag="4")] + pub creates: ::prost::alloc::vec::Vec, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransferEvent { +pub struct Transfer { /// trace information #[prost(string, tag="1")] pub trx_id: ::prost::alloc::string::String, @@ -96,8 +102,6 @@ pub struct TransferEvent { /// contract & scope #[prost(string, tag="3")] pub contract: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub action: ::prost::alloc::string::String, #[prost(string, tag="5")] pub symcode: ::prost::alloc::string::String, /// data payload @@ -122,4 +126,103 @@ pub struct TransferEvent { #[prost(message, optional, tag="14")] pub timestamp: ::core::option::Option<::prost_types::Timestamp>, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Issue { + /// trace information + #[prost(string, tag="1")] + pub trx_id: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub action_index: u32, + /// contract & scope + #[prost(string, tag="3")] + pub contract: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub symcode: ::prost::alloc::string::String, + /// data payload + #[prost(string, tag="5")] + pub issuer: ::prost::alloc::string::String, + #[prost(string, tag="6")] + pub to: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub quantity: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub memo: ::prost::alloc::string::String, + /// extras + #[prost(uint32, tag="9")] + pub precision: u32, + #[prost(int64, tag="10")] + pub amount: i64, + #[prost(double, tag="11")] + pub value: f64, + /// block information + #[prost(uint64, tag="12")] + pub block_num: u64, + #[prost(message, optional, tag="13")] + pub timestamp: ::core::option::Option<::prost_types::Timestamp>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Retire { + /// trace information + #[prost(string, tag="1")] + pub trx_id: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub action_index: u32, + /// contract & scope + #[prost(string, tag="3")] + pub contract: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub symcode: ::prost::alloc::string::String, + /// data payload + #[prost(string, tag="6")] + pub from: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub quantity: ::prost::alloc::string::String, + #[prost(string, tag="8")] + pub memo: ::prost::alloc::string::String, + /// extras + #[prost(uint32, tag="9")] + pub precision: u32, + #[prost(int64, tag="10")] + pub amount: i64, + #[prost(double, tag="11")] + pub value: f64, + /// block information + #[prost(uint64, tag="12")] + pub block_num: u64, + #[prost(message, optional, tag="13")] + pub timestamp: ::core::option::Option<::prost_types::Timestamp>, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Create { + /// trace information + #[prost(string, tag="1")] + pub trx_id: ::prost::alloc::string::String, + #[prost(uint32, tag="2")] + pub action_index: u32, + /// contract & scope + #[prost(string, tag="3")] + pub contract: ::prost::alloc::string::String, + #[prost(string, tag="5")] + pub symcode: ::prost::alloc::string::String, + /// data payload + #[prost(string, tag="6")] + pub issuer: ::prost::alloc::string::String, + #[prost(string, tag="7")] + pub maximum_supply: ::prost::alloc::string::String, + /// extras + #[prost(uint32, tag="8")] + pub precision: u32, + #[prost(int64, tag="9")] + pub amount: i64, + #[prost(double, tag="10")] + pub value: f64, + /// block information + #[prost(uint64, tag="11")] + pub block_num: u64, + #[prost(message, optional, tag="12")] + pub timestamp: ::core::option::Option<::prost_types::Timestamp>, +} // @@protoc_insertion_point(module) diff --git a/src/sinks.rs b/src/sinks.rs index 45227c0..2d0d679 100644 --- a/src/sinks.rs +++ b/src/sinks.rs @@ -3,18 +3,18 @@ use substreams::errors::Error; use substreams_database_change::pb::database::{table_change, DatabaseChanges}; use substreams_entity_change::pb::entity::EntityChanges; -use crate::eosio_token::{Accounts, Stats, TransferEvents}; +use crate::eosio_token::{Accounts, Stats, Events}; use crate::utils::to_key; #[substreams::handlers::map] pub fn graph_out( map_accounts: Accounts, map_stats: Stats, - map_transfers: TransferEvents, + map_events: Events, ) -> Result { let mut tables = substreams_entity_change::tables::Tables::new(); - for account in map_accounts.items { + for account in map_accounts.changes { let key = to_key(&account.trx_id, account.action_index); tables .create_row("accounts", key) @@ -34,7 +34,7 @@ pub fn graph_out( .set("value", account.value.to_string()); } - for stat in map_stats.items { + for stat in map_stats.changes { let key = to_key(&stat.trx_id, stat.action_index); tables .create_row("stats", key) @@ -55,7 +55,7 @@ pub fn graph_out( .set("value", stat.value.to_string()); } - for transfer in map_transfers.items { + for transfer in map_events.transfers { let key = to_key(&transfer.trx_id, transfer.action_index); tables .create_row("transfers", key) @@ -64,7 +64,6 @@ pub fn graph_out( .set("action_index", transfer.action_index.to_string()) // contract & scope .set("contract", transfer.contract.to_string()) - .set("action", transfer.action.to_string()) .set("symcode", transfer.symcode.to_string()) // data payload .set("from", transfer.from.to_string()) @@ -77,6 +76,66 @@ pub fn graph_out( .set("value", transfer.value.to_string()); } + for issue in map_events.issues { + let key = to_key(&issue.trx_id, issue.action_index); + tables + .create_row("issues", key) + // transaction + .set("trx_id", issue.trx_id.to_string()) + .set("action_index", issue.action_index.to_string()) + // contract & scope + .set("contract", issue.contract.to_string()) + .set("symcode", issue.symcode.to_string()) + // data payload + .set("issuer", issue.issuer.to_string()) + .set("to", issue.to.to_string()) + .set("memo", issue.memo.to_string()) + .set("quantity", issue.quantity.to_string()) + // extras + .set("amount", issue.amount.to_string()) + .set("precision", issue.precision.to_string()) + .set("value", issue.value.to_string()); + } + + for retire in map_events.retires { + let key = to_key(&retire.trx_id, retire.action_index); + tables + .create_row("retires", key) + // transaction + .set("trx_id", retire.trx_id.to_string()) + .set("action_index", retire.action_index.to_string()) + // contract & scope + .set("contract", retire.contract.to_string()) + .set("symcode", retire.symcode.to_string()) + // data payload + .set("quantity", retire.quantity.to_string()) + .set("from", retire.from.to_string()) + .set("memo", retire.memo.to_string()) + // extras + .set("amount", retire.amount.to_string()) + .set("precision", retire.precision.to_string()) + .set("value", retire.value.to_string()); + } + + for create in map_events.creates { + let key = to_key(&create.trx_id, create.action_index); + tables + .create_row("creates", key) + // transaction + .set("trx_id", create.trx_id.to_string()) + .set("action_index", create.action_index.to_string()) + // contract & scope + .set("contract", create.contract.to_string()) + .set("symcode", create.symcode.to_string()) + // data payload + .set("issuer", create.issuer.to_string()) + .set("maximum_supply", create.maximum_supply.to_string()) + // extras + .set("amount", create.amount.to_string()) + .set("precision", create.precision.to_string()) + .set("value", create.value.to_string()); + } + Ok(tables.to_entity_changes()) } @@ -84,11 +143,11 @@ pub fn graph_out( pub fn ch_out( map_accounts: Accounts, map_stats: Stats, - map_transfers: TransferEvents, + map_events: Events, ) -> Result { let mut tables = DatabaseChanges::default(); - for account in map_accounts.items { + for account in map_accounts.changes { let keys = HashMap::from([ ("account".to_string(), account.account.to_string()), ("block_num".to_string(), account.block_num.to_string()), @@ -108,7 +167,7 @@ pub fn ch_out( .change("timestamp", ("", account.timestamp.unwrap().to_string().as_str())); } - for stat in map_stats.items { + for stat in map_stats.changes { let keys = HashMap::from([ ("contract".to_string(), stat.contract.to_string()), ("block_num".to_string(), stat.block_num.to_string()), @@ -129,7 +188,7 @@ pub fn ch_out( .change("timestamp", ("", stat.timestamp.unwrap().to_string().as_str())); } - for transfer in map_transfers.items { + for transfer in map_events.transfers { let keys = HashMap::from([ ("trx_id".to_string(), transfer.trx_id), ("action_index".to_string(), transfer.action_index.to_string()), @@ -138,7 +197,6 @@ pub fn ch_out( tables .push_change_composite("transfer_events", keys, 0, table_change::Operation::Create) .change("contract", ("", transfer.contract.to_string().as_str())) - .change("action", ("", transfer.action.to_string().as_str())) .change("symcode", ("", transfer.symcode.to_string().as_str())) .change("from", ("", transfer.from.to_string().as_str())) .change("to", ("", transfer.to.to_string().as_str())) diff --git a/substreams.yaml b/substreams.yaml index 7217c3d..7f2b0b9 100644 --- a/substreams.yaml +++ b/substreams.yaml @@ -1,13 +1,13 @@ specVersion: v0.1.0 package: name: antelope_tokens - version: v0.3.9 + version: v0.4.0 url: https://github.com/pinax-network/substreams-antelope-tokens doc: Antelope `eosio.token` based action traces & database operations. imports: entities: https://github.com/streamingfast/substreams-sink-entity-changes/releases/download/v1.3.1/substreams-sink-entity-changes-v1.3.1.spkg - database_change: https://github.com/streamingfast/substreams-database-change/releases/download/v1.0.0/substreams-database-change-v1.0.0.spkg + database_change: https://github.com/streamingfast/substreams-database-change/releases/download/v1.3.1/substreams-database-change-v1.3.1.spkg sql: https://github.com/streamingfast/substreams-sink-sql/releases/download/protodefs-v1.0.3/substreams-sink-sql-protodefs-v1.0.3.spkg binaries: @@ -22,12 +22,12 @@ protobuf: - ./proto/v1 modules: - - name: map_transfers + - name: map_events kind: map inputs: - source: sf.antelope.type.v1.Block output: - type: proto:antelope.eosio.token.v1.TransferEvents + type: proto:antelope.eosio.token.v1.Events - name: map_accounts kind: map @@ -48,7 +48,7 @@ modules: inputs: - map: map_accounts - map: map_stat - - map: map_transfers + - map: map_events output: type: proto:sf.substreams.sink.entity.v1.EntityChanges @@ -57,7 +57,7 @@ modules: inputs: - map: map_accounts - map: map_stat - - map: map_transfers + - map: map_events output: type: proto:sf.substreams.sink.database.v1.DatabaseChanges