feat(substreams): add substreams for Uniswap v2 and v3
This commit is contained in:
28
substreams/ethereum-uniswap-v3/Cargo.toml
Normal file
28
substreams/ethereum-uniswap-v3/Cargo.toml
Normal file
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "substreams-ethereum-uniswap-v3"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "substreams_ethereum_uniswap_v3"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
substreams.workspace = true
|
||||
substreams-ethereum.workspace = true
|
||||
prost.workspace = true
|
||||
ethabi.workspace = true
|
||||
anyhow = { workspace = true, features = [] }
|
||||
hex-literal.workspace = true
|
||||
substreams-helper.workspace = true
|
||||
num-bigint = "0.4.4"
|
||||
hex.workspace = true
|
||||
tiny-keccak = "2.0"
|
||||
substreams-entity-change = "1.3"
|
||||
|
||||
[target.wasm32-unknown-unknown.dependencies]
|
||||
getrandom = { version = "0.2", features = ["custom"] }
|
||||
|
||||
[build-dependencies]
|
||||
anyhow.workspace = true
|
||||
substreams-ethereum.workspace = true
|
||||
2
substreams/ethereum-uniswap-v3/Makefile
Normal file
2
substreams/ethereum-uniswap-v3/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
build:
|
||||
cargo build --target wasm32-unknown-unknown --profile substreams
|
||||
198
substreams/ethereum-uniswap-v3/abi/Factory.json
Normal file
198
substreams/ethereum-uniswap-v3/abi/Factory.json
Normal file
@@ -0,0 +1,198 @@
|
||||
[
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickSpacing",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "FeeAmountEnabled",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "oldOwner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "newOwner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "OwnerChanged",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token0",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token1",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int24",
|
||||
"name": "tickSpacing",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "pool",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "PoolCreated",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenA",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenB",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
}
|
||||
],
|
||||
"name": "createPool",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pool",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickSpacing",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "enableFeeAmount",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
}
|
||||
],
|
||||
"name": "feeAmountTickSpacing",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenA",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "tokenB",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "fee",
|
||||
"type": "uint24"
|
||||
}
|
||||
],
|
||||
"name": "getPool",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "pool",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "owner",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_owner",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "setOwner",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
988
substreams/ethereum-uniswap-v3/abi/Pool.json
Normal file
988
substreams/ethereum-uniswap-v3/abi/Pool.json
Normal file
@@ -0,0 +1,988 @@
|
||||
[
|
||||
{
|
||||
"inputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Burn",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "Collect",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "CollectProtocol",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "paid0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "paid1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Flash",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinalityNextOld",
|
||||
"type": "uint16"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinalityNextNew",
|
||||
"type": "uint16"
|
||||
}
|
||||
],
|
||||
"name": "IncreaseObservationCardinalityNext",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceX96",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int24",
|
||||
"name": "tick",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "Initialize",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "amount",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Mint",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol0Old",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol1Old",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol0New",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol1New",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"name": "SetFeeProtocol",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int256",
|
||||
"name": "amount0",
|
||||
"type": "int256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int256",
|
||||
"name": "amount1",
|
||||
"type": "int256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceX96",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint128",
|
||||
"name": "liquidity",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "int24",
|
||||
"name": "tick",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "Swap",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "burn",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount0Requested",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount1Requested",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "collect",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount0Requested",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount1Requested",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"name": "collectProtocol",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "factory",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "fee",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint24",
|
||||
"name": "",
|
||||
"type": "uint24"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "feeGrowthGlobal0X128",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "feeGrowthGlobal1X128",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "flash",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinalityNext",
|
||||
"type": "uint16"
|
||||
}
|
||||
],
|
||||
"name": "increaseObservationCardinalityNext",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceX96",
|
||||
"type": "uint160"
|
||||
}
|
||||
],
|
||||
"name": "initialize",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "liquidity",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "maxLiquidityPerTick",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "amount",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "mint",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "index",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "observations",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint32",
|
||||
"name": "blockTimestamp",
|
||||
"type": "uint32"
|
||||
},
|
||||
{
|
||||
"internalType": "int56",
|
||||
"name": "tickCumulative",
|
||||
"type": "int56"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "secondsPerLiquidityCumulativeX128",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "initialized",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint32[]",
|
||||
"name": "secondsAgos",
|
||||
"type": "uint32[]"
|
||||
}
|
||||
],
|
||||
"name": "observe",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int56[]",
|
||||
"name": "tickCumulatives",
|
||||
"type": "int56[]"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160[]",
|
||||
"name": "secondsPerLiquidityCumulativeX128s",
|
||||
"type": "uint160[]"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "key",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "positions",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "_liquidity",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "feeGrowthInside0LastX128",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "feeGrowthInside1LastX128",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "tokensOwed0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "tokensOwed1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "protocolFees",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "token0",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "token1",
|
||||
"type": "uint128"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol0",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol1",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"name": "setFeeProtocol",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "slot0",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceX96",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tick",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "uint16",
|
||||
"name": "observationIndex",
|
||||
"type": "uint16"
|
||||
},
|
||||
{
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinality",
|
||||
"type": "uint16"
|
||||
},
|
||||
{
|
||||
"internalType": "uint16",
|
||||
"name": "observationCardinalityNext",
|
||||
"type": "uint16"
|
||||
},
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "feeProtocol",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "unlocked",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickLower",
|
||||
"type": "int24"
|
||||
},
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tickUpper",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "snapshotCumulativesInside",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int56",
|
||||
"name": "tickCumulativeInside",
|
||||
"type": "int56"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "secondsPerLiquidityInsideX128",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "uint32",
|
||||
"name": "secondsInside",
|
||||
"type": "uint32"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "recipient",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "zeroForOne",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"internalType": "int256",
|
||||
"name": "amountSpecified",
|
||||
"type": "int256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "sqrtPriceLimitX96",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "swap",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int256",
|
||||
"name": "amount0",
|
||||
"type": "int256"
|
||||
},
|
||||
{
|
||||
"internalType": "int256",
|
||||
"name": "amount1",
|
||||
"type": "int256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "int16",
|
||||
"name": "wordPosition",
|
||||
"type": "int16"
|
||||
}
|
||||
],
|
||||
"name": "tickBitmap",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "tickSpacing",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "int24",
|
||||
"name": "tick",
|
||||
"type": "int24"
|
||||
}
|
||||
],
|
||||
"name": "ticks",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint128",
|
||||
"name": "liquidityGross",
|
||||
"type": "uint128"
|
||||
},
|
||||
{
|
||||
"internalType": "int128",
|
||||
"name": "liquidityNet",
|
||||
"type": "int128"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "feeGrowthOutside0X128",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "feeGrowthOutside1X128",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "int56",
|
||||
"name": "tickCumulativeOutside",
|
||||
"type": "int56"
|
||||
},
|
||||
{
|
||||
"internalType": "uint160",
|
||||
"name": "secondsPerLiquidityOutsideX128",
|
||||
"type": "uint160"
|
||||
},
|
||||
{
|
||||
"internalType": "uint32",
|
||||
"name": "secondsOutside",
|
||||
"type": "uint32"
|
||||
},
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "initialized",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "token0",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "token1",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
67
substreams/ethereum-uniswap-v3/arbitrum-uniswap-v3.yaml
Normal file
67
substreams/ethereum-uniswap-v3/arbitrum-uniswap-v3.yaml
Normal file
@@ -0,0 +1,67 @@
|
||||
specVersion: v0.1.0
|
||||
package:
|
||||
name: "substreams_arbitrum_uniswap_v3"
|
||||
version: v0.2.0
|
||||
|
||||
protobuf:
|
||||
files:
|
||||
- tycho/evm/v1/common.proto
|
||||
- tycho/evm/v1/entity.proto
|
||||
- uniswap.proto
|
||||
importPaths:
|
||||
- ./proto/v1
|
||||
- ../../proto/
|
||||
|
||||
binaries:
|
||||
default:
|
||||
type: wasm/rust-v1
|
||||
file: ../../target/wasm32-unknown-unknown/substreams/substreams_ethereum_uniswap_v3.wasm
|
||||
|
||||
modules:
|
||||
- name: map_pools_created
|
||||
kind: map
|
||||
initialBlock: 37418321
|
||||
inputs:
|
||||
- params: string
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
- name: store_pools
|
||||
kind: store
|
||||
initialBlock: 37418321
|
||||
updatePolicy: set_if_not_exists
|
||||
valueType: proto:uniswap.v3.Pool
|
||||
inputs:
|
||||
- map: map_pools_created
|
||||
|
||||
- name: map_balance_changes
|
||||
kind: map
|
||||
initialBlock: 37418321
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- store: store_pools
|
||||
output:
|
||||
type: proto:tycho.evm.uniswap.v3.BalanceDeltas
|
||||
|
||||
- name: store_pools_balances
|
||||
kind: store
|
||||
initialBlock: 37418321
|
||||
updatePolicy: add
|
||||
valueType: bigint
|
||||
inputs:
|
||||
- map: map_balance_changes
|
||||
|
||||
- name: map_pool_events
|
||||
kind: map
|
||||
initialBlock: 37418321
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- map: map_pools_created
|
||||
- store: store_pools
|
||||
- store: store_pools_balances
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
params:
|
||||
map_pools_created: "1F98431c8aD98523631AE4a59f267346ea31F984"
|
||||
12
substreams/ethereum-uniswap-v3/build.rs
Normal file
12
substreams/ethereum-uniswap-v3/build.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
use anyhow::{Ok, Result};
|
||||
use substreams_ethereum::Abigen;
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
Abigen::new("Factory", "abi/Factory.json")?
|
||||
.generate()?
|
||||
.write_to_file("src/abi/factory.rs")?;
|
||||
Abigen::new("Pool", "abi/Pool.json")?
|
||||
.generate()?
|
||||
.write_to_file("src/abi/pool.rs")?;
|
||||
Ok(())
|
||||
}
|
||||
67
substreams/ethereum-uniswap-v3/ethereum-uniswap-v3.yaml
Normal file
67
substreams/ethereum-uniswap-v3/ethereum-uniswap-v3.yaml
Normal file
@@ -0,0 +1,67 @@
|
||||
specVersion: v0.1.0
|
||||
package:
|
||||
name: "substreams_ethereum_uniswap_v3"
|
||||
version: v0.2.0
|
||||
|
||||
protobuf:
|
||||
files:
|
||||
- tycho/evm/v1/common.proto
|
||||
- tycho/evm/v1/entity.proto
|
||||
- uniswap.proto
|
||||
importPaths:
|
||||
- ./proto/v1
|
||||
- ../../proto/
|
||||
|
||||
binaries:
|
||||
default:
|
||||
type: wasm/rust-v1
|
||||
file: ../../target/wasm32-unknown-unknown/substreams/substreams_ethereum_uniswap_v3.wasm
|
||||
|
||||
modules:
|
||||
- name: map_pools_created
|
||||
kind: map
|
||||
initialBlock: 12369621
|
||||
inputs:
|
||||
- params: string
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
- name: store_pools
|
||||
kind: store
|
||||
initialBlock: 12369621
|
||||
updatePolicy: set_if_not_exists
|
||||
valueType: proto:uniswap.v3.Pool
|
||||
inputs:
|
||||
- map: map_pools_created
|
||||
|
||||
- name: map_balance_changes
|
||||
kind: map
|
||||
initialBlock: 12369621
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- store: store_pools
|
||||
output:
|
||||
type: proto:tycho.evm.uniswap.v3.BalanceDeltas
|
||||
|
||||
- name: store_pools_balances
|
||||
kind: store
|
||||
initialBlock: 12369621
|
||||
updatePolicy: add
|
||||
valueType: bigint
|
||||
inputs:
|
||||
- map: map_balance_changes
|
||||
|
||||
- name: map_pool_events
|
||||
kind: map
|
||||
initialBlock: 12369621
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- map: map_pools_created
|
||||
- store: store_pools
|
||||
- store: store_pools_balances
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
params:
|
||||
map_pools_created: "1F98431c8aD98523631AE4a59f267346ea31F984"
|
||||
29
substreams/ethereum-uniswap-v3/proto/v1/uniswap.proto
Normal file
29
substreams/ethereum-uniswap-v3/proto/v1/uniswap.proto
Normal file
@@ -0,0 +1,29 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package uniswap.v3;
|
||||
|
||||
message Pool {
|
||||
bytes address = 1;
|
||||
bytes token0 = 2;
|
||||
bytes token1 = 3;
|
||||
bytes created_tx_hash = 4;
|
||||
}
|
||||
|
||||
// A change to a pool's balance.
|
||||
message BalanceDelta {
|
||||
// The address of the ERC20 token.
|
||||
bytes token_address = 1;
|
||||
// The delta of the token.
|
||||
bytes amount = 2;
|
||||
// The sign of the delta, true for positive, false for negative.
|
||||
bool sign = 3;
|
||||
// The address of the pool whose balance changed.
|
||||
bytes pool_address = 4;
|
||||
// Used to determine the order of the balance changes. Necessary for the balance store.
|
||||
uint64 ordinal = 5;
|
||||
}
|
||||
|
||||
// A group of BalanceDelta
|
||||
message BalanceDeltas {
|
||||
repeated BalanceDelta deltas = 1;
|
||||
}
|
||||
1040
substreams/ethereum-uniswap-v3/src/abi/factory.rs
Normal file
1040
substreams/ethereum-uniswap-v3/src/abi/factory.rs
Normal file
File diff suppressed because it is too large
Load Diff
4
substreams/ethereum-uniswap-v3/src/abi/mod.rs
Normal file
4
substreams/ethereum-uniswap-v3/src/abi/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#![allow(clippy::all, clippy::pedantic, clippy::nursery)]
|
||||
|
||||
pub mod factory;
|
||||
pub mod pool;
|
||||
5153
substreams/ethereum-uniswap-v3/src/abi/pool.rs
Normal file
5153
substreams/ethereum-uniswap-v3/src/abi/pool.rs
Normal file
File diff suppressed because it is too large
Load Diff
45
substreams/ethereum-uniswap-v3/src/events/burn.rs
Normal file
45
substreams/ethereum-uniswap-v3/src/events/burn.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
use substreams_helper::storage_change::StorageChangesFilter;
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::Burn,
|
||||
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
|
||||
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
|
||||
};
|
||||
|
||||
use super::{BalanceDelta, EventTrait};
|
||||
|
||||
impl EventTrait for Burn {
|
||||
fn get_changed_attributes(
|
||||
&self,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute> {
|
||||
let storage_vec = storage_changes.to_vec();
|
||||
|
||||
let filtered_storage_changes = storage_vec
|
||||
.filter_by_address(pool_address)
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
|
||||
|
||||
let mut changed_attributes =
|
||||
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect());
|
||||
|
||||
let changed_ticks =
|
||||
pool_storage.get_ticks_changes(vec![&self.tick_upper, &self.tick_lower]);
|
||||
|
||||
changed_attributes.extend(changed_ticks);
|
||||
|
||||
changed_attributes
|
||||
}
|
||||
|
||||
fn get_balance_delta(&self, _pool: &Pool, _ordinal: u64) -> Vec<BalanceDelta> {
|
||||
// Burn event balances deltas are accounted for by the Collect event.
|
||||
// In the case of a burn, the Collect event amounts will include both the burned amount and
|
||||
// the fees earned.
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
58
substreams/ethereum-uniswap-v3/src/events/collect.rs
Normal file
58
substreams/ethereum-uniswap-v3/src/events/collect.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::Collect,
|
||||
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
|
||||
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
|
||||
};
|
||||
use substreams_helper::storage_change::StorageChangesFilter;
|
||||
|
||||
use super::{BalanceDelta, EventTrait};
|
||||
|
||||
impl EventTrait for Collect {
|
||||
fn get_changed_attributes(
|
||||
&self,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute> {
|
||||
let storage_vec = storage_changes.to_vec();
|
||||
|
||||
let filtered_storage_changes = storage_vec
|
||||
.filter_by_address(pool_address)
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
|
||||
|
||||
let mut changed_attributes =
|
||||
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect());
|
||||
|
||||
let changed_ticks =
|
||||
pool_storage.get_ticks_changes(vec![&self.tick_upper, &self.tick_lower]);
|
||||
|
||||
changed_attributes.extend(changed_ticks);
|
||||
|
||||
changed_attributes
|
||||
}
|
||||
|
||||
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
|
||||
let changed_balance = vec![
|
||||
BalanceDelta {
|
||||
token_address: pool.token0.clone(),
|
||||
amount: self.amount0.clone().to_bytes_le().1,
|
||||
sign: false,
|
||||
pool_address: pool.address.clone(),
|
||||
ordinal,
|
||||
},
|
||||
BalanceDelta {
|
||||
token_address: pool.token1.clone(),
|
||||
amount: self.amount1.clone().to_bytes_le().1,
|
||||
sign: false,
|
||||
pool_address: pool.address.clone(),
|
||||
ordinal,
|
||||
},
|
||||
];
|
||||
changed_balance
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
use substreams_helper::storage_change::StorageChangesFilter;
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::CollectProtocol,
|
||||
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
|
||||
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
|
||||
};
|
||||
|
||||
use super::{BalanceDelta, EventTrait};
|
||||
|
||||
impl EventTrait for CollectProtocol {
|
||||
fn get_changed_attributes(
|
||||
&self,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute> {
|
||||
let storage_vec = storage_changes.to_vec();
|
||||
|
||||
let filtered_storage_changes = storage_vec
|
||||
.filter_by_address(pool_address)
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
|
||||
|
||||
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
|
||||
}
|
||||
|
||||
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
|
||||
let changed_balance = vec![
|
||||
BalanceDelta {
|
||||
token_address: pool.token0.clone(),
|
||||
amount: self.amount0.clone().to_bytes_le().1,
|
||||
sign: false,
|
||||
pool_address: pool.address.clone(),
|
||||
ordinal,
|
||||
},
|
||||
BalanceDelta {
|
||||
token_address: pool.token1.clone(),
|
||||
amount: self.amount1.clone().to_bytes_le().1,
|
||||
sign: false,
|
||||
pool_address: pool.address.clone(),
|
||||
ordinal,
|
||||
},
|
||||
];
|
||||
changed_balance
|
||||
}
|
||||
}
|
||||
50
substreams/ethereum-uniswap-v3/src/events/flash.rs
Normal file
50
substreams/ethereum-uniswap-v3/src/events/flash.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::Flash,
|
||||
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
|
||||
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
|
||||
};
|
||||
use substreams_helper::storage_change::StorageChangesFilter;
|
||||
|
||||
use super::{BalanceDelta, EventTrait};
|
||||
|
||||
impl EventTrait for Flash {
|
||||
fn get_changed_attributes(
|
||||
&self,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute> {
|
||||
let storage_vec = storage_changes.to_vec();
|
||||
|
||||
let filtered_storage_changes = storage_vec
|
||||
.filter_by_address(pool_address)
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
|
||||
|
||||
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
|
||||
}
|
||||
|
||||
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
|
||||
let changed_balance = vec![
|
||||
BalanceDelta {
|
||||
token_address: pool.token0.clone(),
|
||||
amount: self.paid0.clone().to_bytes_le().1,
|
||||
sign: true,
|
||||
pool_address: pool.address.clone(),
|
||||
ordinal,
|
||||
},
|
||||
BalanceDelta {
|
||||
token_address: pool.token1.clone(),
|
||||
amount: self.paid1.clone().to_bytes_le().1,
|
||||
sign: true,
|
||||
pool_address: pool.address.clone(),
|
||||
ordinal,
|
||||
},
|
||||
];
|
||||
changed_balance
|
||||
}
|
||||
}
|
||||
34
substreams/ethereum-uniswap-v3/src/events/initialize.rs
Normal file
34
substreams/ethereum-uniswap-v3/src/events/initialize.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::Initialize,
|
||||
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
|
||||
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
|
||||
};
|
||||
use substreams_helper::storage_change::StorageChangesFilter;
|
||||
|
||||
use super::{BalanceDelta, EventTrait};
|
||||
|
||||
impl EventTrait for Initialize {
|
||||
fn get_changed_attributes(
|
||||
&self,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute> {
|
||||
let storage_vec = storage_changes.to_vec();
|
||||
|
||||
let filtered_storage_changes = storage_vec
|
||||
.filter_by_address(pool_address)
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
|
||||
|
||||
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
|
||||
}
|
||||
|
||||
fn get_balance_delta(&self, _pool: &Pool, _ordinal: u64) -> Vec<BalanceDelta> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
58
substreams/ethereum-uniswap-v3/src/events/mint.rs
Normal file
58
substreams/ethereum-uniswap-v3/src/events/mint.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::Mint,
|
||||
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
|
||||
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
|
||||
};
|
||||
use substreams_helper::storage_change::StorageChangesFilter;
|
||||
|
||||
use super::{BalanceDelta, EventTrait};
|
||||
|
||||
impl EventTrait for Mint {
|
||||
fn get_changed_attributes(
|
||||
&self,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute> {
|
||||
let storage_vec = storage_changes.to_vec();
|
||||
|
||||
let filtered_storage_changes = storage_vec
|
||||
.filter_by_address(pool_address)
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
|
||||
|
||||
let mut changed_attributes =
|
||||
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect());
|
||||
|
||||
let changed_ticks =
|
||||
pool_storage.get_ticks_changes(vec![&self.tick_upper, &self.tick_lower]);
|
||||
|
||||
changed_attributes.extend(changed_ticks);
|
||||
|
||||
changed_attributes
|
||||
}
|
||||
|
||||
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
|
||||
let changed_balance = vec![
|
||||
BalanceDelta {
|
||||
token_address: pool.token0.clone(),
|
||||
amount: self.amount0.clone().to_bytes_le().1,
|
||||
sign: true,
|
||||
pool_address: pool.address.clone(),
|
||||
ordinal,
|
||||
},
|
||||
BalanceDelta {
|
||||
token_address: pool.token1.clone(),
|
||||
amount: self.amount1.clone().to_bytes_le().1,
|
||||
sign: true,
|
||||
pool_address: pool.address.clone(),
|
||||
ordinal,
|
||||
},
|
||||
];
|
||||
changed_balance
|
||||
}
|
||||
}
|
||||
150
substreams/ethereum-uniswap-v3/src/events/mod.rs
Normal file
150
substreams/ethereum-uniswap-v3/src/events/mod.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
use substreams_ethereum::{
|
||||
pb::eth::v2::{Log, StorageChange},
|
||||
Event,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::{
|
||||
Burn, Collect, CollectProtocol, Flash, Initialize, Mint, SetFeeProtocol, Swap,
|
||||
},
|
||||
pb::{
|
||||
tycho::evm::v1::Attribute,
|
||||
uniswap::v3::{BalanceDelta, Pool},
|
||||
},
|
||||
};
|
||||
|
||||
pub mod burn;
|
||||
pub mod collect;
|
||||
pub mod collect_fee_protocol;
|
||||
pub mod flash;
|
||||
pub mod initialize;
|
||||
pub mod mint;
|
||||
pub mod set_fee_protocol;
|
||||
pub mod swap;
|
||||
|
||||
/// A trait for extracting changed attributes and balance from an event.
|
||||
pub trait EventTrait {
|
||||
/// Get all relevant changed attributes from the `[StorageChange]`.
|
||||
/// If an attribute is changed multiple times, only the last state will be returned.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `storage_changes` - A slice of `StorageChange` that indicates the changes in storage.
|
||||
/// * `pool` - Reference to the `Pool`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `Attribute` that represents the changed attributes.
|
||||
fn get_changed_attributes(
|
||||
&self,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute>;
|
||||
|
||||
/// Get all balance deltas from the event.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `pool` - Reference to the `Pool`.
|
||||
/// * `ordinal` - The ordinal number of the event. This is used by the balance store to sort the
|
||||
/// balance deltas in the correct order.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `BalanceDelta` that represents the balance deltas.
|
||||
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta>;
|
||||
}
|
||||
|
||||
/// Represent every events of a UniswapV3 pool.
|
||||
pub enum EventType {
|
||||
Initialize(Initialize),
|
||||
Swap(Swap),
|
||||
Flash(Flash),
|
||||
Mint(Mint),
|
||||
Burn(Burn),
|
||||
Collect(Collect),
|
||||
SetFeeProtocol(SetFeeProtocol),
|
||||
CollectProtocol(CollectProtocol),
|
||||
}
|
||||
|
||||
impl EventType {
|
||||
fn as_event_trait(&self) -> &dyn EventTrait {
|
||||
match self {
|
||||
EventType::Initialize(e) => e,
|
||||
EventType::Swap(e) => e,
|
||||
EventType::Flash(e) => e,
|
||||
EventType::Mint(e) => e,
|
||||
EventType::Burn(e) => e,
|
||||
EventType::Collect(e) => e,
|
||||
EventType::SetFeeProtocol(e) => e,
|
||||
EventType::CollectProtocol(e) => e,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes a given log into an `EventType`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `event` - A reference to the `Log`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// An `Option<EventType>` that represents the decoded event type.
|
||||
pub fn decode_event(event: &Log) -> Option<EventType> {
|
||||
[
|
||||
Initialize::match_and_decode(event).map(EventType::Initialize),
|
||||
Swap::match_and_decode(event).map(EventType::Swap),
|
||||
Flash::match_and_decode(event).map(EventType::Flash),
|
||||
Mint::match_and_decode(event).map(EventType::Mint),
|
||||
Burn::match_and_decode(event).map(EventType::Burn),
|
||||
Collect::match_and_decode(event).map(EventType::Collect),
|
||||
SetFeeProtocol::match_and_decode(event).map(EventType::SetFeeProtocol),
|
||||
CollectProtocol::match_and_decode(event).map(EventType::CollectProtocol),
|
||||
]
|
||||
.into_iter()
|
||||
.find_map(std::convert::identity)
|
||||
}
|
||||
|
||||
/// Gets the changed attributes from the log.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `event` - A reference to the `Log`.
|
||||
/// * `storage_changes` - A slice of `StorageChange` that indicates the changes in storage.
|
||||
/// * `pool` - Reference to the `Pool` structure.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `Attribute` that represents the changed attributes.
|
||||
pub fn get_log_changed_attributes(
|
||||
event: &Log,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute> {
|
||||
decode_event(event)
|
||||
.map(|e| {
|
||||
e.as_event_trait()
|
||||
.get_changed_attributes(storage_changes, pool_address)
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Gets the changed balances from the log.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `event` - A reference to the `Log`.
|
||||
/// * `pool` - Reference to the `Pool` structure.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A vector of `BalanceDelta` that represents
|
||||
pub fn get_log_changed_balances(event: &Log, pool: &Pool) -> Vec<BalanceDelta> {
|
||||
decode_event(event)
|
||||
.map(|e| {
|
||||
e.as_event_trait()
|
||||
.get_balance_delta(pool, event.ordinal)
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::SetFeeProtocol,
|
||||
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
|
||||
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
|
||||
};
|
||||
use substreams_helper::storage_change::StorageChangesFilter;
|
||||
|
||||
use super::{BalanceDelta, EventTrait};
|
||||
|
||||
impl EventTrait for SetFeeProtocol {
|
||||
fn get_changed_attributes(
|
||||
&self,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute> {
|
||||
let storage_vec = storage_changes.to_vec();
|
||||
|
||||
let filtered_storage_changes = storage_vec
|
||||
.filter_by_address(pool_address)
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
|
||||
|
||||
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
|
||||
}
|
||||
|
||||
fn get_balance_delta(&self, _pool: &Pool, _ordinal: u64) -> Vec<BalanceDelta> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
50
substreams/ethereum-uniswap-v3/src/events/swap.rs
Normal file
50
substreams/ethereum-uniswap-v3/src/events/swap.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use num_bigint::Sign;
|
||||
use substreams::scalar::BigInt;
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
use substreams_helper::storage_change::StorageChangesFilter;
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::Swap,
|
||||
pb::{tycho::evm::v1::Attribute, uniswap::v3::Pool},
|
||||
storage::{constants::TRACKED_SLOTS, pool_storage::UniswapPoolStorage},
|
||||
};
|
||||
|
||||
use super::{BalanceDelta, EventTrait};
|
||||
|
||||
impl EventTrait for Swap {
|
||||
fn get_changed_attributes(
|
||||
&self,
|
||||
storage_changes: &[StorageChange],
|
||||
pool_address: &[u8; 20],
|
||||
) -> Vec<Attribute> {
|
||||
let storage_vec = storage_changes.to_vec();
|
||||
|
||||
let filtered_storage_changes = storage_vec
|
||||
.filter_by_address(pool_address)
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let pool_storage = UniswapPoolStorage::new(&filtered_storage_changes);
|
||||
|
||||
pool_storage.get_changed_attributes(TRACKED_SLOTS.to_vec().iter().collect())
|
||||
}
|
||||
|
||||
fn get_balance_delta(&self, pool: &Pool, ordinal: u64) -> Vec<BalanceDelta> {
|
||||
let create_balance_delta = |token_address: Vec<u8>, amount: BigInt| -> BalanceDelta {
|
||||
let (amount_sign, amount_bytes) = amount.clone().to_bytes_le();
|
||||
BalanceDelta {
|
||||
token_address,
|
||||
amount: amount_bytes,
|
||||
sign: amount_sign == Sign::Plus,
|
||||
pool_address: pool.address.clone(),
|
||||
ordinal,
|
||||
}
|
||||
};
|
||||
|
||||
vec![
|
||||
create_balance_delta(pool.token0.clone(), self.amount0.clone()),
|
||||
create_balance_delta(pool.token1.clone(), self.amount1.clone()),
|
||||
]
|
||||
}
|
||||
}
|
||||
11
substreams/ethereum-uniswap-v3/src/lib.rs
Normal file
11
substreams/ethereum-uniswap-v3/src/lib.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
#![allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
|
||||
mod abi;
|
||||
mod modules;
|
||||
mod pb;
|
||||
mod storage;
|
||||
|
||||
pub use modules::*;
|
||||
|
||||
mod events;
|
||||
mod traits;
|
||||
103
substreams/ethereum-uniswap-v3/src/modules/1_map_pool_created.rs
Normal file
103
substreams/ethereum-uniswap-v3/src/modules/1_map_pool_created.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use ethabi::ethereum_types::Address;
|
||||
use substreams::scalar::BigInt;
|
||||
use substreams_ethereum::pb::eth::v2::{self as eth};
|
||||
|
||||
use substreams_helper::{event_handler::EventHandler, hex::Hexable};
|
||||
|
||||
use crate::{
|
||||
abi::factory::events::PoolCreated,
|
||||
pb::tycho::evm::v1::{
|
||||
Attribute, BlockChanges, ChangeType, EntityChanges, FinancialType, ImplementationType,
|
||||
ProtocolComponent, ProtocolType, Transaction, TransactionChanges,
|
||||
},
|
||||
};
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_pools_created(
|
||||
params: String,
|
||||
block: eth::Block,
|
||||
) -> Result<BlockChanges, substreams::errors::Error> {
|
||||
let mut new_pools: Vec<TransactionChanges> = vec![];
|
||||
let factory_address = params.as_str();
|
||||
|
||||
get_new_pools(&block, &mut new_pools, factory_address);
|
||||
|
||||
Ok(BlockChanges { block: Some(block.into()), changes: new_pools })
|
||||
}
|
||||
|
||||
// Extract new pools from PoolCreated events
|
||||
fn get_new_pools(
|
||||
block: ð::Block,
|
||||
new_pools: &mut Vec<TransactionChanges>,
|
||||
factory_address: &str,
|
||||
) {
|
||||
// Extract new pools from PoolCreated events
|
||||
let mut on_pool_created = |event: PoolCreated, _tx: ð::TransactionTrace, _log: ð::Log| {
|
||||
let tycho_tx: Transaction = _tx.into();
|
||||
|
||||
new_pools.push(TransactionChanges {
|
||||
tx: Some(tycho_tx.clone()),
|
||||
contract_changes: vec![],
|
||||
entity_changes: vec![EntityChanges {
|
||||
component_id: event.pool.to_hex(),
|
||||
attributes: vec![
|
||||
Attribute {
|
||||
name: "liquidity".to_string(),
|
||||
value: BigInt::from(0).to_signed_bytes_le(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "tick".to_string(),
|
||||
value: BigInt::from(0).to_signed_bytes_le(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "sqrt_price_x96".to_string(),
|
||||
value: BigInt::from(0).to_signed_bytes_le(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
],
|
||||
}],
|
||||
component_changes: vec![ProtocolComponent {
|
||||
id: event.pool.to_hex(),
|
||||
tokens: vec![event.token0, event.token1],
|
||||
contracts: vec![],
|
||||
static_att: vec![
|
||||
Attribute {
|
||||
name: "fee".to_string(),
|
||||
value: event.fee.to_signed_bytes_le(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "tick_spacing".to_string(),
|
||||
value: event.tick_spacing.to_signed_bytes_le(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "pool_address".to_string(),
|
||||
value: event.pool,
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
],
|
||||
change: i32::from(ChangeType::Creation),
|
||||
protocol_type: Option::from(ProtocolType {
|
||||
name: "uniswap_v3_pool".to_string(),
|
||||
financial_type: FinancialType::Swap.into(),
|
||||
attribute_schema: vec![],
|
||||
implementation_type: ImplementationType::Custom.into(),
|
||||
}),
|
||||
tx: Some(tycho_tx),
|
||||
}],
|
||||
balance_changes: vec![],
|
||||
})
|
||||
};
|
||||
|
||||
let mut eh = EventHandler::new(block);
|
||||
|
||||
eh.filter_by_address(vec![Address::from_str(factory_address).unwrap()]);
|
||||
|
||||
eh.on::<PoolCreated, _>(&mut on_pool_created);
|
||||
eh.handle_events();
|
||||
}
|
||||
23
substreams/ethereum-uniswap-v3/src/modules/2_store_pools.rs
Normal file
23
substreams/ethereum-uniswap-v3/src/modules/2_store_pools.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use std::str;
|
||||
|
||||
use substreams::store::{StoreNew, StoreSetIfNotExists, StoreSetIfNotExistsProto};
|
||||
|
||||
use crate::pb::{tycho::evm::v1::BlockChanges, uniswap::v3::Pool};
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_pools(pools_created: BlockChanges, store: StoreSetIfNotExistsProto<Pool>) {
|
||||
// Store pools. Required so the next maps can match any event to a known pool by their address
|
||||
|
||||
for change in pools_created.changes {
|
||||
for component_change in &change.component_changes {
|
||||
let pool_address: &str = &component_change.id;
|
||||
let pool: Pool = Pool {
|
||||
address: hex::decode(pool_address.trim_start_matches("0x")).unwrap(),
|
||||
token0: component_change.tokens[0].clone(),
|
||||
token1: component_change.tokens[1].clone(),
|
||||
created_tx_hash: change.tx.as_ref().unwrap().hash.clone(),
|
||||
};
|
||||
store.set_if_not_exists(0, format!("{}:{}", "Pool", pool_address), &pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
use anyhow::Ok;
|
||||
use substreams::store::{StoreGet, StoreGetProto};
|
||||
use substreams_ethereum::pb::eth::v2::{self as eth};
|
||||
use substreams_helper::hex::Hexable;
|
||||
|
||||
use crate::{
|
||||
events::get_log_changed_balances,
|
||||
pb::uniswap::v3::{BalanceDeltas, Pool},
|
||||
};
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_balance_changes(
|
||||
block: eth::Block,
|
||||
pools_store: StoreGetProto<Pool>,
|
||||
) -> Result<BalanceDeltas, anyhow::Error> {
|
||||
let mut balances_deltas = Vec::new();
|
||||
for trx in block.transactions() {
|
||||
let mut tx_deltas = Vec::new();
|
||||
for log in trx
|
||||
.calls
|
||||
.iter()
|
||||
.filter(|call| !call.state_reverted)
|
||||
.flat_map(|call| &call.logs)
|
||||
{
|
||||
// Skip if the log is not from a known uniswapV3 pool.
|
||||
if let Some(pool) =
|
||||
pools_store.get_last(format!("{}:{}", "Pool", &log.address.to_hex()))
|
||||
{
|
||||
tx_deltas.extend(get_log_changed_balances(log, &pool))
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if !tx_deltas.is_empty() {
|
||||
balances_deltas.extend(tx_deltas);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(BalanceDeltas { deltas: balances_deltas })
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
use crate::pb::uniswap::v3::BalanceDeltas;
|
||||
use num_bigint::Sign;
|
||||
use substreams::{
|
||||
scalar::BigInt,
|
||||
store::{StoreAdd, StoreAddBigInt, StoreNew},
|
||||
};
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_pools_balances(balances_deltas: BalanceDeltas, store: StoreAddBigInt) {
|
||||
let mut deltas = balances_deltas.deltas.clone();
|
||||
|
||||
deltas.sort_unstable_by_key(|delta| delta.ordinal);
|
||||
|
||||
deltas.iter().for_each(|delta| {
|
||||
store.add(
|
||||
delta.ordinal,
|
||||
format!(
|
||||
"pool:{0}:token:{1}",
|
||||
hex::encode(&delta.pool_address),
|
||||
hex::encode(&delta.token_address)
|
||||
),
|
||||
BigInt::from_bytes_le(
|
||||
if delta.sign { Sign::Plus } else { Sign::Minus },
|
||||
delta.amount.as_slice(),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
235
substreams/ethereum-uniswap-v3/src/modules/5_map_pool_events.rs
Normal file
235
substreams/ethereum-uniswap-v3/src/modules/5_map_pool_events.rs
Normal file
@@ -0,0 +1,235 @@
|
||||
use std::{collections::HashMap, usize, vec};
|
||||
use substreams::store::{StoreGet, StoreGetBigInt, StoreGetProto};
|
||||
use substreams_ethereum::pb::eth::v2::{self as eth, TransactionTrace};
|
||||
|
||||
use substreams_helper::hex::Hexable;
|
||||
|
||||
use crate::{
|
||||
events::{get_log_changed_attributes, get_log_changed_balances},
|
||||
pb::{
|
||||
tycho::evm::v1::{BalanceChange, Block, BlockChanges, EntityChanges, TransactionChanges},
|
||||
uniswap::v3::Pool,
|
||||
},
|
||||
};
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_pool_events(
|
||||
block: eth::Block,
|
||||
created_pools: BlockChanges,
|
||||
pools_store: StoreGetProto<Pool>,
|
||||
balance_store: StoreGetBigInt,
|
||||
) -> Result<BlockChanges, substreams::errors::Error> {
|
||||
let mut tx_changes_map: HashMap<Vec<u8>, TransactionChanges> = HashMap::new();
|
||||
|
||||
// Add created pools to the tx_changes_map
|
||||
for change in created_pools.changes.into_iter() {
|
||||
let transaction = change.tx.as_ref().unwrap();
|
||||
tx_changes_map
|
||||
.entry(transaction.hash.clone())
|
||||
.and_modify(|c| {
|
||||
c.component_changes
|
||||
.extend(change.component_changes.clone());
|
||||
c.entity_changes
|
||||
.extend(change.entity_changes.clone());
|
||||
})
|
||||
.or_insert(change);
|
||||
}
|
||||
|
||||
for trx in block.transactions() {
|
||||
for (log, call_view) in trx.logs_with_calls() {
|
||||
// Skip if the log is not from a known uniswapV3 pool.
|
||||
if let Some(pool) =
|
||||
pools_store.get_last(format!("{}:{}", "Pool", &log.address.to_hex()))
|
||||
{
|
||||
let changed_attributes = get_log_changed_attributes(
|
||||
log,
|
||||
&call_view.call.storage_changes,
|
||||
pool.address
|
||||
.clone()
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.expect("Pool address is not 20 bytes long"),
|
||||
);
|
||||
|
||||
let mut balance_changes: Vec<BalanceChange> = vec![];
|
||||
|
||||
if !(get_log_changed_balances(log, &pool).is_empty()) {
|
||||
let token_0_balance = balance_store.get_last(format!(
|
||||
"pool:{0}:token:{1}",
|
||||
hex::encode(&pool.address),
|
||||
hex::encode(&pool.token0)
|
||||
));
|
||||
let token_1_balance = balance_store.get_last(format!(
|
||||
"pool:{0}:token:{1}",
|
||||
hex::encode(&pool.address),
|
||||
hex::encode(&pool.token1)
|
||||
));
|
||||
|
||||
let pool_address_utf8 = pool
|
||||
.address
|
||||
.clone()
|
||||
.to_hex()
|
||||
.as_bytes()
|
||||
.to_vec();
|
||||
|
||||
let token_0_balance_change = BalanceChange {
|
||||
component_id: pool_address_utf8.clone(),
|
||||
token: pool.token0.clone(),
|
||||
balance: token_0_balance
|
||||
.clone()
|
||||
.expect("Couldn't get balance from store")
|
||||
.to_bytes_be()
|
||||
.1,
|
||||
};
|
||||
let token_1_balance_change = BalanceChange {
|
||||
component_id: pool_address_utf8.clone(),
|
||||
token: pool.token1.clone(),
|
||||
balance: token_1_balance
|
||||
.clone()
|
||||
.expect("Couldn't get balance from store")
|
||||
.to_bytes_be()
|
||||
.1,
|
||||
};
|
||||
|
||||
balance_changes.extend([token_0_balance_change, token_1_balance_change]);
|
||||
}
|
||||
|
||||
// Create entity changes
|
||||
let entity_changes: Vec<EntityChanges> = vec![EntityChanges {
|
||||
component_id: pool.address.clone().to_hex(),
|
||||
attributes: changed_attributes,
|
||||
}];
|
||||
|
||||
update_tx_changes_map(entity_changes, balance_changes, &mut tx_changes_map, trx);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make a list of all HashMap values:
|
||||
let tx_entity_changes: Vec<TransactionChanges> = tx_changes_map.into_values().collect();
|
||||
|
||||
let tycho_block: Block = block.into();
|
||||
|
||||
let block_entity_changes =
|
||||
BlockChanges { block: Some(tycho_block), changes: tx_entity_changes };
|
||||
|
||||
Ok(block_entity_changes)
|
||||
}
|
||||
|
||||
fn update_tx_changes_map(
|
||||
entity_changes: Vec<EntityChanges>,
|
||||
balance_changes: Vec<BalanceChange>,
|
||||
tx_changes_map: &mut HashMap<Vec<u8>, TransactionChanges>,
|
||||
tx_trace: &TransactionTrace,
|
||||
) {
|
||||
// Get the tx hash
|
||||
let tx_hash = tx_trace.hash.clone();
|
||||
|
||||
// Get the tx changes from the map
|
||||
let tx_changes = tx_changes_map.get_mut(&tx_hash);
|
||||
|
||||
// Update the tx changes
|
||||
if let Some(tx_changes) = tx_changes {
|
||||
// Merge the entity changes
|
||||
tx_changes.entity_changes =
|
||||
merge_entity_changes(&tx_changes.entity_changes, &entity_changes);
|
||||
|
||||
// Merge the balance changes
|
||||
tx_changes.balance_changes =
|
||||
merge_balance_changes(&tx_changes.balance_changes, &balance_changes);
|
||||
} else {
|
||||
// If the tx is not in the map, add it
|
||||
let tx_changes = TransactionChanges {
|
||||
tx: Some(tx_trace.into()),
|
||||
contract_changes: vec![],
|
||||
entity_changes,
|
||||
balance_changes,
|
||||
component_changes: vec![],
|
||||
};
|
||||
tx_changes_map.insert(tx_hash, tx_changes);
|
||||
}
|
||||
}
|
||||
|
||||
/// Merges new entity changes into an existing collection of entity changes and returns the merged
|
||||
/// result. For each entity change, if an entity change with the same component_id exists, its
|
||||
/// attributes are merged. If an attribute with the same name exists, the new attribute replaces the
|
||||
/// old one.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - `existing_changes`: A reference to a vector of existing entity changes.
|
||||
/// - `new_changes`: A reference to a vector of new entity changes to be merged.
|
||||
///
|
||||
/// Returns:
|
||||
/// A new `Vec<EntityChanges>` containing the merged entity changes.
|
||||
fn merge_entity_changes(
|
||||
existing_changes: &[EntityChanges],
|
||||
new_changes: &Vec<EntityChanges>,
|
||||
) -> Vec<EntityChanges> {
|
||||
let mut changes_map = existing_changes
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|change| (change.component_id.clone(), change))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
for change in new_changes {
|
||||
match changes_map.get_mut(&change.component_id) {
|
||||
Some(existing_change) => {
|
||||
let mut attributes_map = existing_change
|
||||
.attributes
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|attr| (attr.name.clone(), attr))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
for attr in &change.attributes {
|
||||
attributes_map.insert(attr.name.clone(), attr.clone());
|
||||
}
|
||||
|
||||
existing_change.attributes = attributes_map.into_values().collect();
|
||||
}
|
||||
None => {
|
||||
changes_map.insert(change.component_id.clone(), change.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changes_map.into_values().collect()
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
struct BalanceChangeKey {
|
||||
token: Vec<u8>,
|
||||
component_id: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Merges two vectors of `BalanceChange` structures into a single vector. If two `BalanceChange`
|
||||
/// instances have the same combination of `token` and `component_id`, the value from the
|
||||
/// `new_entries` vector will replace the one from the `current` vector.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - `current`: A reference to a vector of `BalanceChange` instances representing the current
|
||||
/// balance changes.
|
||||
/// - `new_entries`: A reference to a vector of `BalanceChange` instances representing new balance
|
||||
/// changes to be merged.
|
||||
///
|
||||
/// Returns:
|
||||
/// A `Vec<BalanceChange>` that contains the merged balance changes.
|
||||
fn merge_balance_changes(
|
||||
current: &[BalanceChange],
|
||||
new_entries: &Vec<BalanceChange>,
|
||||
) -> Vec<BalanceChange> {
|
||||
let mut balances = HashMap::new();
|
||||
|
||||
for balance_change in current.iter().chain(new_entries) {
|
||||
let key = BalanceChangeKey {
|
||||
token: balance_change.token.clone(),
|
||||
component_id: balance_change.component_id.clone(),
|
||||
};
|
||||
|
||||
balances.insert(key, balance_change.clone());
|
||||
}
|
||||
|
||||
balances.into_values().collect()
|
||||
}
|
||||
18
substreams/ethereum-uniswap-v3/src/modules/mod.rs
Normal file
18
substreams/ethereum-uniswap-v3/src/modules/mod.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
pub use map_pool_created::map_pools_created;
|
||||
pub use map_pool_events::map_pool_events;
|
||||
pub use store_pools::store_pools;
|
||||
|
||||
#[path = "1_map_pool_created.rs"]
|
||||
mod map_pool_created;
|
||||
|
||||
#[path = "2_store_pools.rs"]
|
||||
mod store_pools;
|
||||
|
||||
#[path = "3_map_balance_changes.rs"]
|
||||
mod map_balance_changes;
|
||||
|
||||
#[path = "4_store_pools_balances.rs"]
|
||||
mod store_pools_balances;
|
||||
|
||||
#[path = "5_map_pool_events.rs"]
|
||||
mod map_pool_events;
|
||||
17
substreams/ethereum-uniswap-v3/src/pb/mod.rs
Normal file
17
substreams/ethereum-uniswap-v3/src/pb/mod.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
// @generated
|
||||
pub mod tycho {
|
||||
pub mod evm {
|
||||
// @@protoc_insertion_point(attribute:tycho.evm.v1)
|
||||
pub mod v1 {
|
||||
include!("tycho.evm.v1.rs");
|
||||
// @@protoc_insertion_point(tycho.evm.v1)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub mod uniswap {
|
||||
// @@protoc_insertion_point(attribute:uniswap.v3)
|
||||
pub mod v3 {
|
||||
include!("uniswap.v3.rs");
|
||||
// @@protoc_insertion_point(uniswap.v3)
|
||||
}
|
||||
}
|
||||
307
substreams/ethereum-uniswap-v3/src/pb/tycho.evm.v1.rs
Normal file
307
substreams/ethereum-uniswap-v3/src/pb/tycho.evm.v1.rs
Normal file
@@ -0,0 +1,307 @@
|
||||
// @generated
|
||||
// This file contains the proto definitions for Substreams common to all integrations.
|
||||
|
||||
/// A struct describing a block.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Block {
|
||||
/// The blocks hash.
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub hash: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The parent blocks hash.
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub parent_hash: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The block number.
|
||||
#[prost(uint64, tag="3")]
|
||||
pub number: u64,
|
||||
/// The block timestamp.
|
||||
#[prost(uint64, tag="4")]
|
||||
pub ts: u64,
|
||||
}
|
||||
/// A struct describing a transaction.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Transaction {
|
||||
/// The transaction hash.
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub hash: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The sender of the transaction.
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub from: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The receiver of the transaction.
|
||||
#[prost(bytes="vec", tag="3")]
|
||||
pub to: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The transactions index within the block.
|
||||
#[prost(uint64, tag="4")]
|
||||
pub index: u64,
|
||||
}
|
||||
/// A custom struct representing an arbitrary attribute of a protocol component.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Attribute {
|
||||
/// The name of the attribute.
|
||||
#[prost(string, tag="1")]
|
||||
pub name: ::prost::alloc::string::String,
|
||||
/// The value of the attribute.
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub value: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The type of change the attribute underwent.
|
||||
#[prost(enumeration="ChangeType", tag="3")]
|
||||
pub change: i32,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ProtocolType {
|
||||
#[prost(string, tag="1")]
|
||||
pub name: ::prost::alloc::string::String,
|
||||
#[prost(enumeration="FinancialType", tag="2")]
|
||||
pub financial_type: i32,
|
||||
#[prost(message, repeated, tag="3")]
|
||||
pub attribute_schema: ::prost::alloc::vec::Vec<Attribute>,
|
||||
#[prost(enumeration="ImplementationType", tag="4")]
|
||||
pub implementation_type: i32,
|
||||
}
|
||||
/// A struct describing a part of the protocol.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ProtocolComponent {
|
||||
/// A unique identifier for the component within the protocol.
|
||||
/// Can be a stringified address or a string describing the trading pair.
|
||||
#[prost(string, tag="1")]
|
||||
pub id: ::prost::alloc::string::String,
|
||||
/// Addresses of the ERC20 tokens used by the component.
|
||||
#[prost(bytes="vec", repeated, tag="2")]
|
||||
pub tokens: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||
/// Addresses of the contracts used by the component.
|
||||
#[prost(bytes="vec", repeated, tag="3")]
|
||||
pub contracts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||
/// Attributes of the component.
|
||||
/// The inner ChangeType of the attribute has to match the ChangeType of the ProtocolComponent.
|
||||
#[prost(message, repeated, tag="4")]
|
||||
pub static_att: ::prost::alloc::vec::Vec<Attribute>,
|
||||
/// Type of change the component underwent.
|
||||
#[prost(enumeration="ChangeType", tag="5")]
|
||||
pub change: i32,
|
||||
/// / Represents the functionality of the component.
|
||||
#[prost(message, optional, tag="6")]
|
||||
pub protocol_type: ::core::option::Option<ProtocolType>,
|
||||
/// Transaction where this component was created
|
||||
#[prost(message, optional, tag="7")]
|
||||
pub tx: ::core::option::Option<Transaction>,
|
||||
}
|
||||
/// A struct for following the changes of Total Value Locked (TVL) of a protocol component.
|
||||
/// Note that if the ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BalanceChange {
|
||||
/// The address of the ERC20 token whose balance changed.
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub token: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The new balance of the token.
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub balance: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded.
|
||||
#[prost(bytes="vec", tag="3")]
|
||||
pub component_id: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
// Native entities
|
||||
|
||||
/// A component is a set of attributes that are associated with a custom entity.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EntityChanges {
|
||||
/// A unique identifier of the entity within the protocol.
|
||||
#[prost(string, tag="1")]
|
||||
pub component_id: ::prost::alloc::string::String,
|
||||
/// The set of attributes that are associated with the entity.
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub attributes: ::prost::alloc::vec::Vec<Attribute>,
|
||||
}
|
||||
// VM entities
|
||||
|
||||
/// A key value entry into contract storage.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ContractSlot {
|
||||
/// A contract's storage slot.
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub slot: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The new value for this storage slot.
|
||||
#[prost(bytes="vec", tag="3")]
|
||||
pub value: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
/// Changes made to a single contract's state.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ContractChange {
|
||||
/// The contract's address
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub address: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The new balance of the contract, empty bytes indicates no change.
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub balance: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The new code of the contract, empty bytes indicates no change.
|
||||
#[prost(bytes="vec", tag="3")]
|
||||
pub code: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The changes to this contract's slots, empty sequence indicates no change.
|
||||
#[prost(message, repeated, tag="4")]
|
||||
pub slots: ::prost::alloc::vec::Vec<ContractSlot>,
|
||||
/// Whether this is an update, a creation or a deletion.
|
||||
#[prost(enumeration="ChangeType", tag="5")]
|
||||
pub change: i32,
|
||||
}
|
||||
// Aggregate entities
|
||||
|
||||
/// A set of changes aggregated by transaction.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionChanges {
|
||||
/// The transaction instance that results in the changes.
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub tx: ::core::option::Option<Transaction>,
|
||||
/// Contains the changes induced by the above transaction, aggregated on a per-contract basis.
|
||||
/// Contains the contract changes induced by the above transaction, usually for tracking VM components.
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub contract_changes: ::prost::alloc::vec::Vec<ContractChange>,
|
||||
/// Contains the entity changes induced by the above transaction.
|
||||
/// Usually for tracking native components or used for VM extensions (plugins).
|
||||
#[prost(message, repeated, tag="3")]
|
||||
pub entity_changes: ::prost::alloc::vec::Vec<EntityChanges>,
|
||||
/// An array of newly added components.
|
||||
#[prost(message, repeated, tag="4")]
|
||||
pub component_changes: ::prost::alloc::vec::Vec<ProtocolComponent>,
|
||||
/// An array of balance changes to components.
|
||||
#[prost(message, repeated, tag="5")]
|
||||
pub balance_changes: ::prost::alloc::vec::Vec<BalanceChange>,
|
||||
}
|
||||
/// A set of transaction changes within a single block.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BlockChanges {
|
||||
/// The block for which these changes are collectively computed.
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub block: ::core::option::Option<Block>,
|
||||
/// The set of transaction changes observed in the specified block.
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub changes: ::prost::alloc::vec::Vec<TransactionChanges>,
|
||||
}
|
||||
/// Enum to specify the type of a change.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum ChangeType {
|
||||
Unspecified = 0,
|
||||
Update = 1,
|
||||
Creation = 2,
|
||||
Deletion = 3,
|
||||
}
|
||||
impl ChangeType {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
///
|
||||
/// The values are not transformed in any way and thus are considered stable
|
||||
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||
pub fn as_str_name(&self) -> &'static str {
|
||||
match self {
|
||||
ChangeType::Unspecified => "CHANGE_TYPE_UNSPECIFIED",
|
||||
ChangeType::Update => "CHANGE_TYPE_UPDATE",
|
||||
ChangeType::Creation => "CHANGE_TYPE_CREATION",
|
||||
ChangeType::Deletion => "CHANGE_TYPE_DELETION",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||
match value {
|
||||
"CHANGE_TYPE_UNSPECIFIED" => Some(Self::Unspecified),
|
||||
"CHANGE_TYPE_UPDATE" => Some(Self::Update),
|
||||
"CHANGE_TYPE_CREATION" => Some(Self::Creation),
|
||||
"CHANGE_TYPE_DELETION" => Some(Self::Deletion),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum FinancialType {
|
||||
Swap = 0,
|
||||
Lend = 1,
|
||||
Leverage = 2,
|
||||
Psm = 3,
|
||||
}
|
||||
impl FinancialType {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
///
|
||||
/// The values are not transformed in any way and thus are considered stable
|
||||
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||
pub fn as_str_name(&self) -> &'static str {
|
||||
match self {
|
||||
FinancialType::Swap => "SWAP",
|
||||
FinancialType::Lend => "LEND",
|
||||
FinancialType::Leverage => "LEVERAGE",
|
||||
FinancialType::Psm => "PSM",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||
match value {
|
||||
"SWAP" => Some(Self::Swap),
|
||||
"LEND" => Some(Self::Lend),
|
||||
"LEVERAGE" => Some(Self::Leverage),
|
||||
"PSM" => Some(Self::Psm),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum ImplementationType {
|
||||
Vm = 0,
|
||||
Custom = 1,
|
||||
}
|
||||
impl ImplementationType {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
///
|
||||
/// The values are not transformed in any way and thus are considered stable
|
||||
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||
pub fn as_str_name(&self) -> &'static str {
|
||||
match self {
|
||||
ImplementationType::Vm => "VM",
|
||||
ImplementationType::Custom => "CUSTOM",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||
match value {
|
||||
"VM" => Some(Self::Vm),
|
||||
"CUSTOM" => Some(Self::Custom),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
// WARNING: DEPRECATED. Please use common.proto's TransactionChanges and BlockChanges instead.
|
||||
// This file contains the definition for the native integration of Substreams.
|
||||
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionEntityChanges {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub tx: ::core::option::Option<Transaction>,
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub entity_changes: ::prost::alloc::vec::Vec<EntityChanges>,
|
||||
/// An array of newly added components.
|
||||
#[prost(message, repeated, tag="3")]
|
||||
pub component_changes: ::prost::alloc::vec::Vec<ProtocolComponent>,
|
||||
/// An array of balance changes to components.
|
||||
#[prost(message, repeated, tag="4")]
|
||||
pub balance_changes: ::prost::alloc::vec::Vec<BalanceChange>,
|
||||
}
|
||||
/// A set of transaction changes within a single block.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BlockEntityChanges {
|
||||
/// The block for which these changes are collectively computed.
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub block: ::core::option::Option<Block>,
|
||||
/// The set of transaction changes observed in the specified block.
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub changes: ::prost::alloc::vec::Vec<TransactionEntityChanges>,
|
||||
}
|
||||
// @@protoc_insertion_point(module)
|
||||
541
substreams/ethereum-uniswap-v3/src/pb/uniswap.types.v1.rs
Normal file
541
substreams/ethereum-uniswap-v3/src/pb/uniswap.types.v1.rs
Normal file
@@ -0,0 +1,541 @@
|
||||
// @generated
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Erc20Tokens {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub tokens: ::prost::alloc::vec::Vec<Erc20Token>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Erc20Token {
|
||||
#[prost(string, tag="1")]
|
||||
pub address: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub name: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="3")]
|
||||
pub symbol: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="4")]
|
||||
pub decimals: u64,
|
||||
#[prost(string, tag="5")]
|
||||
pub total_supply: ::prost::alloc::string::String,
|
||||
#[prost(string, repeated, tag="6")]
|
||||
pub whitelist_pools: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Liquidity {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="2")]
|
||||
pub value: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Pools {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub pools: ::prost::alloc::vec::Vec<Pool>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Pool {
|
||||
#[prost(string, tag="1")]
|
||||
pub address: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="3")]
|
||||
pub created_at_timestamp: u64,
|
||||
#[prost(uint64, tag="4")]
|
||||
pub created_at_block_number: u64,
|
||||
#[prost(message, optional, tag="5")]
|
||||
pub token0: ::core::option::Option<Erc20Token>,
|
||||
#[prost(message, optional, tag="6")]
|
||||
pub token1: ::core::option::Option<Erc20Token>,
|
||||
/// Integer
|
||||
#[prost(string, tag="7")]
|
||||
pub fee_tier: ::prost::alloc::string::String,
|
||||
/// internals
|
||||
#[prost(int32, tag="30")]
|
||||
pub tick_spacing: i32,
|
||||
#[prost(uint64, tag="31")]
|
||||
pub log_ordinal: u64,
|
||||
#[prost(string, tag="32")]
|
||||
pub transaction_id: ::prost::alloc::string::String,
|
||||
#[prost(bool, tag="33")]
|
||||
pub ignore_pool: bool,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Events {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub pool_sqrt_prices: ::prost::alloc::vec::Vec<events::PoolSqrtPrice>,
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub pool_liquidities: ::prost::alloc::vec::Vec<events::PoolLiquidity>,
|
||||
#[prost(message, repeated, tag="7")]
|
||||
pub fee_growth_global_updates: ::prost::alloc::vec::Vec<events::FeeGrowthGlobal>,
|
||||
#[prost(message, repeated, tag="10")]
|
||||
pub fee_growth_inside_updates: ::prost::alloc::vec::Vec<events::FeeGrowthInside>,
|
||||
#[prost(message, repeated, tag="11")]
|
||||
pub fee_growth_outside_updates: ::prost::alloc::vec::Vec<events::FeeGrowthOutside>,
|
||||
#[prost(message, repeated, tag="3")]
|
||||
pub pool_events: ::prost::alloc::vec::Vec<events::PoolEvent>,
|
||||
#[prost(message, repeated, tag="4")]
|
||||
pub transactions: ::prost::alloc::vec::Vec<events::Transaction>,
|
||||
#[prost(message, repeated, tag="6")]
|
||||
pub flashes: ::prost::alloc::vec::Vec<events::Flash>,
|
||||
#[prost(message, repeated, tag="8")]
|
||||
pub ticks_created: ::prost::alloc::vec::Vec<events::TickCreated>,
|
||||
#[prost(message, repeated, tag="9")]
|
||||
pub ticks_updated: ::prost::alloc::vec::Vec<events::TickUpdated>,
|
||||
#[prost(message, repeated, tag="20")]
|
||||
pub created_positions: ::prost::alloc::vec::Vec<events::CreatedPosition>,
|
||||
#[prost(message, repeated, tag="21")]
|
||||
pub increase_liquidity_positions: ::prost::alloc::vec::Vec<events::IncreaseLiquidityPosition>,
|
||||
#[prost(message, repeated, tag="22")]
|
||||
pub decrease_liquidity_positions: ::prost::alloc::vec::Vec<events::DecreaseLiquidityPosition>,
|
||||
#[prost(message, repeated, tag="23")]
|
||||
pub collect_positions: ::prost::alloc::vec::Vec<events::CollectPosition>,
|
||||
#[prost(message, repeated, tag="24")]
|
||||
pub transfer_positions: ::prost::alloc::vec::Vec<events::TransferPosition>,
|
||||
}
|
||||
/// Nested message and enum types in `Events`.
|
||||
pub mod events {
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct FeeGrowthGlobal {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="2")]
|
||||
pub ordinal: u64,
|
||||
#[prost(int32, tag="3")]
|
||||
pub token_idx: i32,
|
||||
/// Integer
|
||||
#[prost(string, tag="4")]
|
||||
pub new_value: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct FeeGrowthInside {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
#[prost(int32, tag="2")]
|
||||
pub tick_idx: i32,
|
||||
#[prost(uint64, tag="3")]
|
||||
pub ordinal: u64,
|
||||
/// Integer
|
||||
#[prost(string, tag="4")]
|
||||
pub new_value: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct FeeGrowthOutside {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
#[prost(int32, tag="2")]
|
||||
pub tick_lower: i32,
|
||||
#[prost(int32, tag="3")]
|
||||
pub tick_upper: i32,
|
||||
#[prost(uint64, tag="4")]
|
||||
pub ordinal: u64,
|
||||
/// Integer
|
||||
#[prost(string, tag="5")]
|
||||
pub new_value: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TickCreated {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="2")]
|
||||
pub idx: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="3")]
|
||||
pub log_ordinal: u64,
|
||||
#[prost(uint64, tag="4")]
|
||||
pub created_at_timestamp: u64,
|
||||
#[prost(uint64, tag="5")]
|
||||
pub created_at_block_number: u64,
|
||||
/// Decimal
|
||||
#[prost(string, tag="6")]
|
||||
pub price0: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="7")]
|
||||
pub price1: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="8")]
|
||||
pub amount: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TickUpdated {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="2")]
|
||||
pub idx: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="3")]
|
||||
pub log_ordinal: u64,
|
||||
/// Integer
|
||||
#[prost(string, tag="4")]
|
||||
pub fee_growth_outside_0x_128: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="5")]
|
||||
pub fee_growth_outside_1x_128: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="6")]
|
||||
pub timestamp: u64,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PoolSqrtPrice {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="2")]
|
||||
pub ordinal: u64,
|
||||
/// Integer
|
||||
#[prost(string, tag="3")]
|
||||
pub sqrt_price: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="4")]
|
||||
pub tick: ::prost::alloc::string::String,
|
||||
#[prost(bool, tag="5")]
|
||||
pub initialized: bool,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PoolEvent {
|
||||
#[prost(uint64, tag="100")]
|
||||
pub log_ordinal: u64,
|
||||
#[prost(uint64, tag="101")]
|
||||
pub log_index: u64,
|
||||
#[prost(string, tag="102")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="103")]
|
||||
pub token0: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="104")]
|
||||
pub token1: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="105")]
|
||||
pub fee: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="106")]
|
||||
pub transaction_id: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="107")]
|
||||
pub timestamp: u64,
|
||||
#[prost(uint64, tag="108")]
|
||||
pub created_at_block_number: u64,
|
||||
#[prost(oneof="pool_event::Type", tags="1, 2, 3")]
|
||||
pub r#type: ::core::option::Option<pool_event::Type>,
|
||||
}
|
||||
/// Nested message and enum types in `PoolEvent`.
|
||||
pub mod pool_event {
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Swap {
|
||||
#[prost(string, tag="1")]
|
||||
pub sender: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub recipient: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="3")]
|
||||
pub origin: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="4")]
|
||||
pub amount_0: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="5")]
|
||||
pub amount_1: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="6")]
|
||||
pub sqrt_price: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="7")]
|
||||
pub liquidity: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="8")]
|
||||
pub tick: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Burn {
|
||||
#[prost(string, tag="1")]
|
||||
pub owner: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub origin: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="3")]
|
||||
pub amount: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="4")]
|
||||
pub amount_0: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="5")]
|
||||
pub amount_1: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="6")]
|
||||
pub tick_lower: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="7")]
|
||||
pub tick_upper: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Mint {
|
||||
#[prost(string, tag="1")]
|
||||
pub owner: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub sender: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="3")]
|
||||
pub origin: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="4")]
|
||||
pub amount_0: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="5")]
|
||||
pub amount_1: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="6")]
|
||||
pub tick_lower: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="7")]
|
||||
pub tick_upper: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="8")]
|
||||
pub amount: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Type {
|
||||
#[prost(message, tag="1")]
|
||||
Swap(Swap),
|
||||
#[prost(message, tag="2")]
|
||||
Burn(Burn),
|
||||
#[prost(message, tag="3")]
|
||||
Mint(Mint),
|
||||
}
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PoolLiquidity {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="2")]
|
||||
pub liquidity: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="3")]
|
||||
pub token0: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="4")]
|
||||
pub token1: ::prost::alloc::string::String,
|
||||
/// internals
|
||||
#[prost(uint64, tag="30")]
|
||||
pub log_ordinal: u64,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Flash {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool_address: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="2")]
|
||||
pub fee_growth_global_0x_128: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="3")]
|
||||
pub fee_growth_global_1x_128: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="4")]
|
||||
pub log_ordinal: u64,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Transaction {
|
||||
#[prost(string, tag="1")]
|
||||
pub id: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="2")]
|
||||
pub block_number: u64,
|
||||
#[prost(uint64, tag="3")]
|
||||
pub timestamp: u64,
|
||||
#[prost(uint64, tag="4")]
|
||||
pub gas_used: u64,
|
||||
/// Integer
|
||||
#[prost(string, tag="5")]
|
||||
pub gas_price: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="6")]
|
||||
pub log_ordinal: u64,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PositionEvent {
|
||||
#[prost(oneof="position_event::Type", tags="1, 2, 3, 4, 5")]
|
||||
pub r#type: ::core::option::Option<position_event::Type>,
|
||||
}
|
||||
/// Nested message and enum types in `PositionEvent`.
|
||||
pub mod position_event {
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Type {
|
||||
#[prost(message, tag="1")]
|
||||
CreatedPosition(super::CreatedPosition),
|
||||
#[prost(message, tag="2")]
|
||||
IncreaseLiquidityPosition(super::IncreaseLiquidityPosition),
|
||||
#[prost(message, tag="3")]
|
||||
DecreaseLiquidityPosition(super::DecreaseLiquidityPosition),
|
||||
#[prost(message, tag="4")]
|
||||
CollectPosition(super::CollectPosition),
|
||||
#[prost(message, tag="5")]
|
||||
TransferPosition(super::TransferPosition),
|
||||
}
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct CreatedPosition {
|
||||
#[prost(string, tag="1")]
|
||||
pub token_id: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub pool: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="3")]
|
||||
pub token0: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="4")]
|
||||
pub token1: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="5")]
|
||||
pub tick_lower: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="6")]
|
||||
pub tick_upper: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="7")]
|
||||
pub transaction: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="8")]
|
||||
pub log_ordinal: u64,
|
||||
#[prost(uint64, tag="9")]
|
||||
pub timestamp: u64,
|
||||
#[prost(uint64, tag="10")]
|
||||
pub block_number: u64,
|
||||
/// BigInt
|
||||
#[prost(string, optional, tag="11")]
|
||||
pub fee_growth_inside0_last_x128: ::core::option::Option<::prost::alloc::string::String>,
|
||||
/// BigInt
|
||||
#[prost(string, optional, tag="12")]
|
||||
pub fee_growth_inside1_last_x128: ::core::option::Option<::prost::alloc::string::String>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct IncreaseLiquidityPosition {
|
||||
#[prost(string, tag="1")]
|
||||
pub token_id: ::prost::alloc::string::String,
|
||||
/// BigInt
|
||||
#[prost(string, tag="2")]
|
||||
pub liquidity: ::prost::alloc::string::String,
|
||||
/// BigDecimal
|
||||
#[prost(string, tag="3")]
|
||||
pub deposited_token0: ::prost::alloc::string::String,
|
||||
/// BigDecimal
|
||||
#[prost(string, tag="4")]
|
||||
pub deposited_token1: ::prost::alloc::string::String,
|
||||
/// BigInt
|
||||
#[prost(string, optional, tag="5")]
|
||||
pub fee_growth_inside0_last_x128: ::core::option::Option<::prost::alloc::string::String>,
|
||||
/// BigInt
|
||||
#[prost(string, optional, tag="6")]
|
||||
pub fee_growth_inside1_last_x128: ::core::option::Option<::prost::alloc::string::String>,
|
||||
#[prost(uint64, tag="10")]
|
||||
pub log_ordinal: u64,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct DecreaseLiquidityPosition {
|
||||
#[prost(string, tag="1")]
|
||||
pub token_id: ::prost::alloc::string::String,
|
||||
/// BigInt
|
||||
#[prost(string, tag="2")]
|
||||
pub liquidity: ::prost::alloc::string::String,
|
||||
/// BigDecimal
|
||||
#[prost(string, tag="3")]
|
||||
pub withdrawn_token0: ::prost::alloc::string::String,
|
||||
/// BigDecimal
|
||||
#[prost(string, tag="4")]
|
||||
pub withdrawn_token1: ::prost::alloc::string::String,
|
||||
/// BigInt
|
||||
#[prost(string, optional, tag="5")]
|
||||
pub fee_growth_inside0_last_x128: ::core::option::Option<::prost::alloc::string::String>,
|
||||
/// BigInt
|
||||
#[prost(string, optional, tag="6")]
|
||||
pub fee_growth_inside1_last_x128: ::core::option::Option<::prost::alloc::string::String>,
|
||||
#[prost(uint64, tag="10")]
|
||||
pub log_ordinal: u64,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct CollectPosition {
|
||||
#[prost(string, tag="1")]
|
||||
pub token_id: ::prost::alloc::string::String,
|
||||
/// BigInt
|
||||
#[prost(string, tag="2")]
|
||||
pub collected_fees_token0: ::prost::alloc::string::String,
|
||||
/// BigInt
|
||||
#[prost(string, tag="3")]
|
||||
pub collected_fees_token1: ::prost::alloc::string::String,
|
||||
/// BigInt
|
||||
#[prost(string, optional, tag="5")]
|
||||
pub fee_growth_inside0_last_x128: ::core::option::Option<::prost::alloc::string::String>,
|
||||
/// BigInt
|
||||
#[prost(string, optional, tag="6")]
|
||||
pub fee_growth_inside1_last_x128: ::core::option::Option<::prost::alloc::string::String>,
|
||||
#[prost(uint64, tag="10")]
|
||||
pub log_ordinal: u64,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransferPosition {
|
||||
#[prost(string, tag="1")]
|
||||
pub token_id: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub owner: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="10")]
|
||||
pub log_ordinal: u64,
|
||||
}
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SnapshotPositions {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub snapshot_positions: ::prost::alloc::vec::Vec<SnapshotPosition>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SnapshotPosition {
|
||||
#[prost(string, tag="1")]
|
||||
pub pool: ::prost::alloc::string::String,
|
||||
/// the token_id of the position
|
||||
#[prost(string, tag="2")]
|
||||
pub position: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="3")]
|
||||
pub block_number: u64,
|
||||
#[prost(string, tag="4")]
|
||||
pub owner: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="6")]
|
||||
pub timestamp: u64,
|
||||
/// Decimal
|
||||
#[prost(string, tag="7")]
|
||||
pub liquidity: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="8")]
|
||||
pub deposited_token0: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="9")]
|
||||
pub deposited_token1: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="10")]
|
||||
pub withdrawn_token0: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="11")]
|
||||
pub withdrawn_token1: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="12")]
|
||||
pub collected_fees_token0: ::prost::alloc::string::String,
|
||||
/// Decimal
|
||||
#[prost(string, tag="13")]
|
||||
pub collected_fees_token1: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="14")]
|
||||
pub transaction: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="15")]
|
||||
pub fee_growth_inside_0_last_x_128: ::prost::alloc::string::String,
|
||||
/// Integer
|
||||
#[prost(string, tag="16")]
|
||||
pub fee_growth_inside_1_last_x_128: ::prost::alloc::string::String,
|
||||
/// internal
|
||||
#[prost(uint64, tag="17")]
|
||||
pub log_ordinal: u64,
|
||||
}
|
||||
// @@protoc_insertion_point(module)
|
||||
41
substreams/ethereum-uniswap-v3/src/pb/uniswap.v3.rs
Normal file
41
substreams/ethereum-uniswap-v3/src/pb/uniswap.v3.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
// @generated
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Pool {
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub address: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub token0: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes="vec", tag="3")]
|
||||
pub token1: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes="vec", tag="4")]
|
||||
pub created_tx_hash: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
/// A change to a pool's balance.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BalanceDelta {
|
||||
/// The address of the ERC20 token.
|
||||
#[prost(bytes="vec", tag="1")]
|
||||
pub token_address: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The delta of the token.
|
||||
#[prost(bytes="vec", tag="2")]
|
||||
pub amount: ::prost::alloc::vec::Vec<u8>,
|
||||
/// The sign of the delta, true for positive, false for negative.
|
||||
#[prost(bool, tag="3")]
|
||||
pub sign: bool,
|
||||
/// The address of the pool whose balance changed.
|
||||
#[prost(bytes="vec", tag="4")]
|
||||
pub pool_address: ::prost::alloc::vec::Vec<u8>,
|
||||
/// Used to determine the order of the balance changes. Necessary for the balance store.
|
||||
#[prost(uint64, tag="5")]
|
||||
pub ordinal: u64,
|
||||
}
|
||||
/// A group of BalanceDelta
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BalanceDeltas {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub deltas: ::prost::alloc::vec::Vec<BalanceDelta>,
|
||||
}
|
||||
// @@protoc_insertion_point(module)
|
||||
60
substreams/ethereum-uniswap-v3/src/storage/constants.rs
Normal file
60
substreams/ethereum-uniswap-v3/src/storage/constants.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
use hex_literal::hex;
|
||||
|
||||
use super::pool_storage::StorageLocation;
|
||||
|
||||
const SLOT0: [u8; 32] = hex!("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
|
||||
const LIQUIDITY_SLOT: StorageLocation = StorageLocation {
|
||||
name: "liquidity",
|
||||
slot: hex!("0000000000000000000000000000000000000000000000000000000000000004"),
|
||||
offset: 0,
|
||||
number_of_bytes: 16,
|
||||
signed: false,
|
||||
};
|
||||
|
||||
const PROTOCOL_FEES_TOKEN_0_SLOT: StorageLocation = StorageLocation {
|
||||
name: "protocol_fees/token0",
|
||||
slot: hex!("0000000000000000000000000000000000000000000000000000000000000003"),
|
||||
offset: 0,
|
||||
number_of_bytes: 16,
|
||||
signed: false,
|
||||
};
|
||||
|
||||
const PROTOCOL_FEES_TOKEN_1_SLOT: StorageLocation = StorageLocation {
|
||||
name: "protocol_fees/token1",
|
||||
slot: hex!("0000000000000000000000000000000000000000000000000000000000000003"),
|
||||
offset: 16,
|
||||
number_of_bytes: 16,
|
||||
signed: false,
|
||||
};
|
||||
|
||||
const SQRT_PRICE_X96_SLOT: StorageLocation = StorageLocation {
|
||||
name: "sqrt_price_x96",
|
||||
slot: SLOT0,
|
||||
offset: 0,
|
||||
number_of_bytes: 20,
|
||||
signed: false,
|
||||
};
|
||||
|
||||
const CURRENT_TICK_SLOT: StorageLocation =
|
||||
StorageLocation { name: "tick", slot: SLOT0, offset: 20, number_of_bytes: 3, signed: true };
|
||||
|
||||
const FEE_PROTOCOL_SLOT: StorageLocation = StorageLocation {
|
||||
name: "fee_protocol",
|
||||
slot: SLOT0,
|
||||
offset: 29,
|
||||
number_of_bytes: 1,
|
||||
signed: false,
|
||||
};
|
||||
|
||||
pub(crate) const TICKS_MAP_SLOT: [u8; 32] =
|
||||
hex!("0000000000000000000000000000000000000000000000000000000000000005");
|
||||
|
||||
pub(crate) const TRACKED_SLOTS: [StorageLocation; 6] = [
|
||||
LIQUIDITY_SLOT,
|
||||
PROTOCOL_FEES_TOKEN_0_SLOT,
|
||||
PROTOCOL_FEES_TOKEN_1_SLOT,
|
||||
SQRT_PRICE_X96_SLOT,
|
||||
CURRENT_TICK_SLOT,
|
||||
FEE_PROTOCOL_SLOT,
|
||||
];
|
||||
4
substreams/ethereum-uniswap-v3/src/storage/mod.rs
Normal file
4
substreams/ethereum-uniswap-v3/src/storage/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod pool_storage;
|
||||
|
||||
pub mod constants;
|
||||
mod utils;
|
||||
132
substreams/ethereum-uniswap-v3/src/storage/pool_storage.rs
Normal file
132
substreams/ethereum-uniswap-v3/src/storage/pool_storage.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
use crate::{
|
||||
pb::tycho::evm::v1::{Attribute, ChangeType},
|
||||
storage::utils,
|
||||
};
|
||||
|
||||
use substreams::scalar::BigInt;
|
||||
use substreams_ethereum::pb::eth::v2::StorageChange;
|
||||
|
||||
use super::{constants::TICKS_MAP_SLOT, utils::read_bytes};
|
||||
|
||||
/// `StorageLocation` is a struct that represents a specific location within a contract's storage
|
||||
/// associated with a name.
|
||||
///
|
||||
/// # Fields
|
||||
///
|
||||
/// * `name` - A string slice (`&str`) reference representing the unique name associated with this
|
||||
/// storage location.
|
||||
/// * `slot` - A fixed-size byte array `[u8; 32]` representing the slot in the contract storage
|
||||
/// where this data is stored. This acts as a primary identifier for the location of the data.
|
||||
/// * `offset` - A usize value indicating the offset in bytes from the start of the slot. This
|
||||
/// allows for fine-grained control and access within a single slot.
|
||||
/// * `number_of_bytes` - A usize value indicating the size of the data in bytes.
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct StorageLocation<'a> {
|
||||
pub name: &'a str,
|
||||
pub slot: [u8; 32],
|
||||
pub offset: usize,
|
||||
pub number_of_bytes: usize,
|
||||
pub signed: bool,
|
||||
}
|
||||
|
||||
pub struct UniswapPoolStorage<'a> {
|
||||
pub storage_changes: &'a Vec<StorageChange>,
|
||||
}
|
||||
|
||||
impl<'a> UniswapPoolStorage<'a> {
|
||||
pub fn new(storage_changes: &'a Vec<StorageChange>) -> UniswapPoolStorage<'a> {
|
||||
Self { storage_changes }
|
||||
}
|
||||
|
||||
/// Iterates through storage changes and checks for modifications in the provided list of
|
||||
/// storage locations. For each change, it compares the old and new values at the specified
|
||||
/// offset and length for that location. If a change is detected, it's added to the returned
|
||||
/// `Attribute` list.
|
||||
///
|
||||
/// Arguments:
|
||||
/// locations: Vec<&StorageLocation> - A vector of references to StorageLocation objects
|
||||
/// that define the slots, offsets, and lengths to be checked for changes.
|
||||
///
|
||||
/// Returns:
|
||||
/// `Vec<Attribute>`: A vector containing Attributes for each change detected in the tracked
|
||||
/// slots. Returns an empty vector if no changes are detected.
|
||||
pub fn get_changed_attributes(&self, locations: Vec<&StorageLocation>) -> Vec<Attribute> {
|
||||
let mut attributes = Vec::new();
|
||||
|
||||
// For each storage change, check if it changes a tracked slot.
|
||||
// If it does, add the attribute to the list of attributes
|
||||
for change in self.storage_changes {
|
||||
for storage_location in locations.iter() {
|
||||
// Check if the change slot matches the tracked slot
|
||||
if change.key == storage_location.slot {
|
||||
let old_data = read_bytes(
|
||||
&change.old_value,
|
||||
storage_location.offset,
|
||||
storage_location.number_of_bytes,
|
||||
);
|
||||
let new_data = read_bytes(
|
||||
&change.new_value,
|
||||
storage_location.offset,
|
||||
storage_location.number_of_bytes,
|
||||
);
|
||||
|
||||
// Check if there is a change in the data
|
||||
if old_data != new_data {
|
||||
let value = match storage_location.signed {
|
||||
true => BigInt::from_signed_bytes_be(new_data),
|
||||
false => BigInt::from_unsigned_bytes_be(new_data),
|
||||
};
|
||||
attributes.push(Attribute {
|
||||
name: storage_location.name.to_string(),
|
||||
value: value.to_signed_bytes_le(),
|
||||
change: ChangeType::Update.into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attributes
|
||||
}
|
||||
|
||||
/// Iterates over a list of tick indexes and checks for modifications in the list of
|
||||
/// storage changes. If a relevent change is detected, it's added to the returned `Attribute`
|
||||
/// list.
|
||||
///
|
||||
/// Arguments:
|
||||
/// ticks_idx: `Vec<&BigInt>` - A vector of references to tick indexes as BigInt objects.
|
||||
///
|
||||
/// Returns:
|
||||
/// `Vec<Attribute>`: A vector containing Attributes for each change detected. Returns an
|
||||
/// empty vector if no changes are detected.
|
||||
///
|
||||
/// Note: Currently, we only track the net-liquidity attribute for each tick.
|
||||
pub fn get_ticks_changes(&self, ticks_idx: Vec<&BigInt>) -> Vec<Attribute> {
|
||||
let mut storage_locs = Vec::new();
|
||||
let mut tick_names = Vec::new();
|
||||
|
||||
// First, create all the names and push them into tick_names.
|
||||
// We need this to keep the references to the names alive until we call
|
||||
// `get_changed_attributes()`
|
||||
for tick_idx in ticks_idx.iter() {
|
||||
tick_names.push(format!("ticks/{}/net-liquidity", tick_idx));
|
||||
}
|
||||
|
||||
// Then, iterate over ticks_idx and tick_names simultaneously
|
||||
for (tick_idx, tick_name) in ticks_idx.iter().zip(tick_names.iter()) {
|
||||
let tick_slot =
|
||||
utils::calc_map_slot(&utils::left_pad_from_bigint(tick_idx), &TICKS_MAP_SLOT);
|
||||
|
||||
storage_locs.push(StorageLocation {
|
||||
name: tick_name,
|
||||
slot: tick_slot,
|
||||
offset: 16,
|
||||
number_of_bytes: 16,
|
||||
signed: true,
|
||||
});
|
||||
}
|
||||
|
||||
self.get_changed_attributes(storage_locs.iter().collect())
|
||||
}
|
||||
}
|
||||
165
substreams/ethereum-uniswap-v3/src/storage/utils.rs
Normal file
165
substreams/ethereum-uniswap-v3/src/storage/utils.rs
Normal file
@@ -0,0 +1,165 @@
|
||||
use substreams::scalar::BigInt;
|
||||
use tiny_keccak::{Hasher, Keccak};
|
||||
|
||||
pub fn calc_map_slot(map_index: &[u8; 32], base_slot: &[u8; 32]) -> [u8; 32] {
|
||||
let mut output = [0u8; 32];
|
||||
let mut hasher = Keccak::v256();
|
||||
hasher.update(map_index);
|
||||
hasher.update(base_slot);
|
||||
hasher.finalize(&mut output);
|
||||
output
|
||||
}
|
||||
|
||||
pub fn left_pad_from_bigint(input: &BigInt) -> [u8; 32] {
|
||||
if input.lt(&BigInt::zero()) {
|
||||
return left_pad(&input.to_signed_bytes_be(), 255);
|
||||
}
|
||||
|
||||
left_pad(&input.to_signed_bytes_be(), 0)
|
||||
}
|
||||
|
||||
pub fn left_pad(input: &[u8], padding_value: u8) -> [u8; 32] {
|
||||
if input.len() > 32 {
|
||||
panic!("cannot convert vec<u8> to H256");
|
||||
}
|
||||
let mut data = [padding_value; 32];
|
||||
let offset = 32 - input.len();
|
||||
data[offset..(input.len() + offset)].copy_from_slice(input);
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
pub fn read_bytes(buf: &[u8], offset: usize, number_of_bytes: usize) -> &[u8] {
|
||||
let buf_length = buf.len();
|
||||
if buf_length < number_of_bytes {
|
||||
panic!(
|
||||
"attempting to read {number_of_bytes} bytes in buffer size {buf_size}",
|
||||
number_of_bytes = number_of_bytes,
|
||||
buf_size = buf.len()
|
||||
)
|
||||
}
|
||||
|
||||
if offset > (buf_length - 1) {
|
||||
panic!(
|
||||
"offset {offset} exceeds buffer size {buf_size}",
|
||||
offset = offset,
|
||||
buf_size = buf.len()
|
||||
)
|
||||
}
|
||||
|
||||
let end = buf_length - 1 - offset;
|
||||
let start_opt = (end + 1).checked_sub(number_of_bytes);
|
||||
if start_opt.is_none() {
|
||||
panic!(
|
||||
"number of bytes {number_of_bytes} with offset {offset} exceeds buffer size
|
||||
{buf_size}",
|
||||
number_of_bytes = number_of_bytes,
|
||||
offset = offset,
|
||||
buf_size = buf.len()
|
||||
)
|
||||
}
|
||||
let start = start_opt.unwrap();
|
||||
|
||||
&buf[start..=end]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::storage::utils::{left_pad, read_bytes};
|
||||
use hex_literal::hex;
|
||||
use std::{fmt::Write, num::ParseIntError};
|
||||
|
||||
#[test]
|
||||
fn left_pad_lt_32_bytes() {
|
||||
let input = hex!("dd62ed3e");
|
||||
assert_eq!(
|
||||
hex!("00000000000000000000000000000000000000000000000000000000dd62ed3e"),
|
||||
left_pad(&input, 0)
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn left_pad_eq_32_bytes() {
|
||||
let input = hex!("00000a0000000000005d000000000000000000000000000000000000dd62ed3e");
|
||||
assert_eq!(
|
||||
hex!("00000a0000000000005d000000000000000000000000000000000000dd62ed3e"),
|
||||
left_pad(&input, 0)
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn left_pad_gt_32_bytes() {
|
||||
let input = hex!("070000000a0000000000005d000000000000000000000000000000000000dd62ed3e");
|
||||
let _ = left_pad(&input, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn read_bytes_buf_too_small() {
|
||||
let buf = decode_hex("ff").unwrap();
|
||||
let offset = 0;
|
||||
let number_of_bytes = 3;
|
||||
let _ = read_bytes(&buf, offset, number_of_bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_one_byte_with_no_offset() {
|
||||
let buf = decode_hex("aabb").unwrap();
|
||||
let offset = 0;
|
||||
let number_of_bytes = 1;
|
||||
assert_eq!(read_bytes(&buf, offset, number_of_bytes), hex!("bb"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_one_byte_with_offset() {
|
||||
let buf = decode_hex("aabb").unwrap();
|
||||
let offset = 1;
|
||||
let number_of_bytes = 1;
|
||||
assert_eq!(read_bytes(&buf, offset, number_of_bytes), hex!("aa"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn read_bytes_overflow() {
|
||||
let buf = decode_hex("aabb").unwrap();
|
||||
let offset = 1;
|
||||
let number_of_bytes = 2;
|
||||
let _ = read_bytes(&buf, offset, number_of_bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_bytes_with_no_offset() {
|
||||
let buf =
|
||||
decode_hex("ffffffffffffffffffffecb6826b89a60000000000000000000013497d94765a").unwrap();
|
||||
let offset = 0;
|
||||
let number_of_bytes = 16;
|
||||
let out = read_bytes(&buf, offset, number_of_bytes);
|
||||
assert_eq!(encode_hex(out), "0000000000000000000013497d94765a".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_byte_with_big_offset() {
|
||||
let buf =
|
||||
decode_hex("0100000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let offset = 31;
|
||||
let number_of_bytes = 1;
|
||||
let out = read_bytes(&buf, offset, number_of_bytes);
|
||||
assert_eq!(encode_hex(out), "01".to_string());
|
||||
}
|
||||
|
||||
fn decode_hex(s: &str) -> Result<Vec<u8>, ParseIntError> {
|
||||
(0..s.len())
|
||||
.step_by(2)
|
||||
.map(|i| u8::from_str_radix(&s[i..i + 2], 16))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn encode_hex(bytes: &[u8]) -> String {
|
||||
let mut s = String::with_capacity(bytes.len() * 2);
|
||||
for &b in bytes {
|
||||
write!(&mut s, "{:02x}", b).unwrap();
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
30
substreams/ethereum-uniswap-v3/src/traits.rs
Normal file
30
substreams/ethereum-uniswap-v3/src/traits.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use substreams_ethereum::pb::eth::v2::{self as eth};
|
||||
|
||||
use crate::pb::tycho::evm::v1::{Block, Transaction};
|
||||
|
||||
impl From<eth::Block> for Block {
|
||||
fn from(block: eth::Block) -> Self {
|
||||
Self {
|
||||
hash: block.hash.clone(),
|
||||
parent_hash: block
|
||||
.header
|
||||
.as_ref()
|
||||
.expect("Block header not present")
|
||||
.parent_hash
|
||||
.clone(),
|
||||
number: block.number,
|
||||
ts: block.timestamp_seconds(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ð::TransactionTrace> for Transaction {
|
||||
fn from(tx: ð::TransactionTrace) -> Self {
|
||||
Self {
|
||||
hash: tx.hash.clone(),
|
||||
from: tx.from.clone(),
|
||||
to: tx.to.clone(),
|
||||
index: tx.index.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user