Skip to content

Commit

Permalink
Add boilerplate for Native balances:
Browse files Browse the repository at this point in the history
ref: #6
  • Loading branch information
DenisCarriere committed Mar 6, 2025
1 parent bb681c4 commit 7d332ba
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 0 deletions.
16 changes: 16 additions & 0 deletions native-balances/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "native-balances"
description = { workspace = true }
edition = { workspace = true }
version = { workspace = true }
authors = [
"Denis <denis@pinax.network>",
"Colin Dickson <https://github.com/colindickson>",
]

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
substreams = { workspace = true }
substreams-ethereum = "0.10"
21 changes: 21 additions & 0 deletions native-balances/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.PHONY: all
all:
make build
substreams info

.PHONY: build
build:
cargo build --target wasm32-unknown-unknown --release
substreams pack

.PHONY: protogen
protogen:
substreams protogen --exclude-paths sf/substreams,google

.PHONY: gui
gui: build
substreams gui substreams.yaml map_events -e eth.substreams.pinax.network:443 --network eth -s 21525891

.PHONY: cache
cache: build
substreams-sink-noop eth.substreams.pinax.network:443 ./substreams.yaml map_events 1:
3 changes: 3 additions & 0 deletions native-balances/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Substreams: `Native Balances`

> Extracts all ETH transfers from Ethereum events.
102 changes: 102 additions & 0 deletions native-balances/src/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use substreams::errors::Error;
use substreams::scalar::{BigInt};
use substreams::Hex;
use substreams_ethereum::pb::eth::v2::{Block, TransactionTraceStatus};
use substreams_ethereum::pb::eth::v2::balance_change::Reason;
use crate::pb::eth::types::v1::{BalanceChange, BalanceChanges};


#[substreams::handlers::map]
pub fn map_balance_changes(block: Block) -> Result<BalanceChanges, Error> {
Ok(BalanceChanges {
balance_changes: map_balance_changes_from_block(block),
})
}

pub fn map_balance_changes_from_block(block: Block) -> Vec<BalanceChange> {
let mut out = Vec::new();
for bc in block.balance_changes.iter() {
let old_value = match bc.old_value.as_ref() {
Some(v) => BigInt::from_unsigned_bytes_be(&v.bytes).to_string(),
None => String::from("0"),
};

let new_value = match bc.new_value.as_ref() {
Some(v) => BigInt::from_unsigned_bytes_be(&v.bytes).to_string(),
None => String::from("0"),
};

out.push(BalanceChange{
address: Hex::encode(&bc.address),
old_value,
new_value,
reason: Reason::from_i32(bc.reason).unwrap().as_str_name().into(),
ordinal: bc.ordinal,
transaction: "".to_string(),
})
}

for trx in block.transaction_traces {
if trx.status == TransactionTraceStatus::Reverted as i32 || trx.status == TransactionTraceStatus::Failed as i32 {
// We need to process gas buy (and refund if transaction reverted) as well as mining rewards when a transaction fails
// because those are still recorded in the state of the blockchain.

let root_call = trx.calls.get(0).unwrap(); // each trx is guaranteed to have a root call

for bc in &root_call.balance_changes {
let reason = Reason::from_i32(bc.reason).unwrap();
if !(reason == Reason::GasBuy || reason == Reason::GasRefund || reason == Reason::RewardTransactionFee) {
continue
}

let old_value = match bc.old_value.as_ref() {
Some(v) => BigInt::from_unsigned_bytes_be(&v.bytes).to_string(),
None => String::from("0"),
};

let new_value = match bc.new_value.as_ref() {
Some(v) => BigInt::from_unsigned_bytes_be(&v.bytes).to_string(),
None => String::from("0"),
};

out.push(BalanceChange{
address: Hex::encode(&bc.address),
old_value,
new_value,
reason: reason.as_str_name().into(),
ordinal: bc.ordinal,
transaction: Hex::encode(&trx.hash),
})
}
}

for call in trx.calls.iter() {
if call.state_reverted {
continue;
}

for bc in call.balance_changes.iter() {
let old_value = match bc.old_value.as_ref() {
Some(v) => BigInt::from_unsigned_bytes_be(&v.bytes).to_string(),
None => String::from("0"),
};

let new_value = match bc.new_value.as_ref() {
Some(v) => BigInt::from_unsigned_bytes_be(&v.bytes).to_string(),
None => String::from("0"),
};

out.push(BalanceChange{
address: Hex::encode(&bc.address),
old_value,
new_value,
reason: Reason::from_i32(bc.reason).unwrap().as_str_name().into(),
ordinal: bc.ordinal,
transaction: Hex::encode(&trx.hash)
})
}
}
}

out
}
1 change: 1 addition & 0 deletions native-balances/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod maps;
9 changes: 9 additions & 0 deletions native-balances/src/maps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use substreams::errors::Error;

use substreams::pb::substreams::Clock;
use substreams_ethereum::pb::eth::v2::{Block};

#[substreams::handlers::map]
pub fn map_events(clock: Clock, block: Block) -> Result<Clock, Error> {
Ok(clock)
}
29 changes: 29 additions & 0 deletions native-balances/substreams.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
specVersion: v0.1.0
package:
name: native_balances
version: v0.1.0
url: https://github.com/pinax-network/substreams-evm-tokens

binaries:
default:
type: wasm/rust-v1
file: ../target/wasm32-unknown-unknown/release/erc20_balances_transfers.wasm

protobuf:
files:
- erc20.proto
importPaths:
- ../proto/v1
excludePaths:
- sf/substreams
- google

modules:
- name: map_events
kind: map
doc: Extracts ERC20 balance changes & transfers
inputs:
- source: sf.substreams.v1.Clock
- source: sf.ethereum.type.v2.Block
output:
type: proto:erc20.types.v1.Events

0 comments on commit 7d332ba

Please sign in to comment.