feat(substreams): add substreams for Uniswap v2 and v3
This commit is contained in:
28
substreams/ethereum-uniswap-v2/Cargo.toml
Normal file
28
substreams/ethereum-uniswap-v2/Cargo.toml
Normal file
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "substreams-ethereum-uniswap-v2"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "ethereum_uniswap_v2"
|
||||
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"
|
||||
itertools = "0.12.1"
|
||||
serde_qs = "0.13.0"
|
||||
serde.workspace = true
|
||||
|
||||
[target.wasm32-unknown-unknown.dependencies]
|
||||
getrandom = { version = "0.2", features = ["custom"] }
|
||||
|
||||
[build-dependencies]
|
||||
anyhow.workspace = true
|
||||
substreams-ethereum.workspace = true
|
||||
2
substreams/ethereum-uniswap-v2/Makefile
Normal file
2
substreams/ethereum-uniswap-v2/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
build:
|
||||
cargo build --target wasm32-unknown-unknown --release
|
||||
125
substreams/ethereum-uniswap-v2/abi/Factory.json
Normal file
125
substreams/ethereum-uniswap-v2/abi/Factory.json
Normal file
@@ -0,0 +1,125 @@
|
||||
[
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "address", "name": "_feeToSetter", "type": "address" }
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token0",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "token1",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "address",
|
||||
"name": "pair",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "PairCreated",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||
"name": "allPairs",
|
||||
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "allPairsLength",
|
||||
"outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "internalType": "address", "name": "tokenA", "type": "address" },
|
||||
{ "internalType": "address", "name": "tokenB", "type": "address" }
|
||||
],
|
||||
"name": "createPair",
|
||||
"outputs": [
|
||||
{ "internalType": "address", "name": "pair", "type": "address" }
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "feeTo",
|
||||
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "feeToSetter",
|
||||
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{ "internalType": "address", "name": "", "type": "address" },
|
||||
{ "internalType": "address", "name": "", "type": "address" }
|
||||
],
|
||||
"name": "getPair",
|
||||
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "internalType": "address", "name": "_feeTo", "type": "address" }
|
||||
],
|
||||
"name": "setFeeTo",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{ "internalType": "address", "name": "_feeToSetter", "type": "address" }
|
||||
],
|
||||
"name": "setFeeToSetter",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
713
substreams/ethereum-uniswap-v2/abi/Pool.json
Normal file
713
substreams/ethereum-uniswap-v2/abi/Pool.json
Normal file
@@ -0,0 +1,713 @@
|
||||
[
|
||||
{
|
||||
"inputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "constructor"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Approval",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "Burn",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Mint",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "sender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0In",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1In",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount0Out",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "amount1Out",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "Swap",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint112",
|
||||
"name": "reserve0",
|
||||
"type": "uint112"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint112",
|
||||
"name": "reserve1",
|
||||
"type": "uint112"
|
||||
}
|
||||
],
|
||||
"name": "Sync",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": true,
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"indexed": false,
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "Transfer",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "DOMAIN_SEPARATOR",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "MINIMUM_LIQUIDITY",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "PERMIT_TYPEHASH",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "allowance",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "approve",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "balanceOf",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "burn",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount0",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount1",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "decimals",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "",
|
||||
"type": "uint8"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "factory",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getReserves",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint112",
|
||||
"name": "_reserve0",
|
||||
"type": "uint112"
|
||||
},
|
||||
{
|
||||
"internalType": "uint112",
|
||||
"name": "_reserve1",
|
||||
"type": "uint112"
|
||||
},
|
||||
{
|
||||
"internalType": "uint32",
|
||||
"name": "_blockTimestampLast",
|
||||
"type": "uint32"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_token0",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_token1",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "initialize",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "kLast",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "mint",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "liquidity",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "name",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "nonces",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "owner",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "spender",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "deadline",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint8",
|
||||
"name": "v",
|
||||
"type": "uint8"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "r",
|
||||
"type": "bytes32"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "s",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "permit",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "price0CumulativeLast",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "price1CumulativeLast",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "skim",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount0Out",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "amount1Out",
|
||||
"type": "uint256"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "data",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"name": "swap",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "symbol",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "string",
|
||||
"name": "",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [],
|
||||
"name": "sync",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "token0",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "token1",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "totalSupply",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transfer",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "from",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "to",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "transferFrom",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bool",
|
||||
"name": "",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
49
substreams/ethereum-uniswap-v2/arbitrum-uniswap-v2.yaml
Normal file
49
substreams/ethereum-uniswap-v2/arbitrum-uniswap-v2.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
specVersion: v0.1.0
|
||||
package:
|
||||
name: "arbitrum_uniswap_v2"
|
||||
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/ethereum_uniswap_v2.wasm
|
||||
|
||||
modules:
|
||||
- name: map_pools_created
|
||||
kind: map
|
||||
initialBlock: 150442611
|
||||
inputs:
|
||||
- params: string
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
- name: store_pools
|
||||
kind: store
|
||||
initialBlock: 150442611
|
||||
updatePolicy: set_if_not_exists
|
||||
valueType: proto:tycho.evm.uniswap.v2.Pool
|
||||
inputs:
|
||||
- map: map_pools_created
|
||||
|
||||
- name: map_pool_events
|
||||
kind: map
|
||||
initialBlock: 150442611
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- map: map_pools_created
|
||||
- store: store_pools
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
params:
|
||||
map_pools_created: factory_address=f1D7CC64Fb4452F05c498126312eBE29f30Fbcf9&protocol_type_name=uniswap_v2_pool
|
||||
12
substreams/ethereum-uniswap-v2/build.rs
Normal file
12
substreams/ethereum-uniswap-v2/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(())
|
||||
}
|
||||
49
substreams/ethereum-uniswap-v2/ethereum-pancakeswap.yaml
Normal file
49
substreams/ethereum-uniswap-v2/ethereum-pancakeswap.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
specVersion: v0.1.0
|
||||
package:
|
||||
name: "ethereum_pancakeswap"
|
||||
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/ethereum_uniswap_v2.wasm
|
||||
|
||||
modules:
|
||||
- name: map_pools_created
|
||||
kind: map
|
||||
initialBlock: 15614590
|
||||
inputs:
|
||||
- params: string
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
- name: store_pools
|
||||
kind: store
|
||||
initialBlock: 15614590
|
||||
updatePolicy: set_if_not_exists
|
||||
valueType: proto:tycho.evm.v1.ProtocolComponent
|
||||
inputs:
|
||||
- map: map_pools_created
|
||||
|
||||
- name: map_pool_events
|
||||
kind: map
|
||||
initialBlock: 15614590
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- map: map_pools_created
|
||||
- store: store_pools
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
params:
|
||||
map_pools_created: factory_address=1097053fd2ea711dad45caccc45eff7548fcb362&protocol_type_name=pancakeswap_pool
|
||||
49
substreams/ethereum-uniswap-v2/ethereum-sushiswap.yaml
Normal file
49
substreams/ethereum-uniswap-v2/ethereum-sushiswap.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
specVersion: v0.1.0
|
||||
package:
|
||||
name: "ethereum_sushiswap_v2"
|
||||
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/ethereum_uniswap_v2.wasm
|
||||
|
||||
modules:
|
||||
- name: map_pools_created
|
||||
kind: map
|
||||
initialBlock: 10794229
|
||||
inputs:
|
||||
- params: string
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
- name: store_pools
|
||||
kind: store
|
||||
initialBlock: 10794229
|
||||
updatePolicy: set_if_not_exists
|
||||
valueType: proto:tycho.evm.uniswap.v2.Pool
|
||||
inputs:
|
||||
- map: map_pools_created
|
||||
|
||||
- name: map_pool_events
|
||||
kind: map
|
||||
initialBlock: 10794229
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- map: map_pools_created
|
||||
- store: store_pools
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
params:
|
||||
map_pools_created: factory_address=c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac&protocol_type_name=sushiswap_v2_pool
|
||||
49
substreams/ethereum-uniswap-v2/ethereum-uniswap-v2.yaml
Normal file
49
substreams/ethereum-uniswap-v2/ethereum-uniswap-v2.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
specVersion: v0.1.0
|
||||
package:
|
||||
name: "ethereum_uniswap_v2"
|
||||
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/ethereum_uniswap_v2.wasm
|
||||
|
||||
modules:
|
||||
- name: map_pools_created
|
||||
kind: map
|
||||
initialBlock: 10008300
|
||||
inputs:
|
||||
- params: string
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
- name: store_pools
|
||||
kind: store
|
||||
initialBlock: 10008300
|
||||
updatePolicy: set_if_not_exists
|
||||
valueType: proto:tycho.evm.uniswap.v2.Pool
|
||||
inputs:
|
||||
- map: map_pools_created
|
||||
|
||||
- name: map_pool_events
|
||||
kind: map
|
||||
initialBlock: 10008300
|
||||
inputs:
|
||||
- source: sf.ethereum.type.v2.Block
|
||||
- map: map_pools_created
|
||||
- store: store_pools
|
||||
output:
|
||||
type: proto:tycho.evm.v1.BlockChanges
|
||||
|
||||
params:
|
||||
map_pools_created: factory_address=5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f&protocol_type_name=uniswap_v2_pool
|
||||
61
substreams/ethereum-uniswap-v2/proto/v1/uniswap.proto
Normal file
61
substreams/ethereum-uniswap-v2/proto/v1/uniswap.proto
Normal file
@@ -0,0 +1,61 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package tycho.evm.uniswap.v2;
|
||||
|
||||
message Pools {
|
||||
repeated Pool pools = 1;
|
||||
}
|
||||
|
||||
message Pool {
|
||||
bytes address = 1;
|
||||
|
||||
bytes token0 = 2;
|
||||
bytes token1 = 3;
|
||||
|
||||
bytes created_tx_hash = 4;
|
||||
}
|
||||
|
||||
message Events {
|
||||
repeated Event events = 1;
|
||||
}
|
||||
|
||||
message Event {
|
||||
oneof type {
|
||||
DepositEvent deposit_type = 10;
|
||||
WithdrawEvent withdraw_type = 20;
|
||||
SyncEvent sync_type = 30;
|
||||
SwapEvent swap_type = 40;
|
||||
}
|
||||
|
||||
string hash = 100;
|
||||
uint32 log_index = 101;
|
||||
uint64 log_ordinal = 102;
|
||||
string to = 103;
|
||||
string from = 104;
|
||||
uint64 block_number = 105;
|
||||
uint64 timestamp = 106;
|
||||
string pool = 107;
|
||||
}
|
||||
|
||||
message DepositEvent {
|
||||
repeated string input_token_amounts = 1;
|
||||
optional string output_token_amount = 2;
|
||||
}
|
||||
|
||||
message WithdrawEvent {
|
||||
repeated string input_token_amounts = 1;
|
||||
optional string output_token_amount = 2;
|
||||
}
|
||||
|
||||
message SyncEvent {
|
||||
string reserve0 = 1;
|
||||
string reserve1 = 2;
|
||||
}
|
||||
|
||||
message SwapEvent {
|
||||
string token_in = 1;
|
||||
string amount_in = 2;
|
||||
|
||||
string token_out = 3;
|
||||
string amount_out = 4;
|
||||
}
|
||||
904
substreams/ethereum-uniswap-v2/src/abi/factory.rs
Normal file
904
substreams/ethereum-uniswap-v2/src/abi/factory.rs
Normal file
@@ -0,0 +1,904 @@
|
||||
const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error";
|
||||
/// Contract's functions.
|
||||
#[allow(dead_code, unused_imports, unused_variables)]
|
||||
pub mod functions {
|
||||
use super::INTERNAL_ERR;
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct AllPairs {
|
||||
pub param0: substreams::scalar::BigInt,
|
||||
}
|
||||
impl AllPairs {
|
||||
const METHOD_ID: [u8; 4] = [30u8, 61u8, 209u8, 139u8];
|
||||
pub fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
let maybe_data = call.input.get(4..);
|
||||
if maybe_data.is_none() {
|
||||
return Err("no data to decode".to_string());
|
||||
}
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Uint(256usize)],
|
||||
maybe_data.unwrap(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode call.input: {:?}", e))?;
|
||||
values.reverse();
|
||||
Ok(Self {
|
||||
param0: {
|
||||
let mut v = [0 as u8; 32];
|
||||
values
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_uint()
|
||||
.expect(INTERNAL_ERR)
|
||||
.to_big_endian(v.as_mut_slice());
|
||||
substreams::scalar::BigInt::from_unsigned_bytes_be(&v)
|
||||
},
|
||||
})
|
||||
}
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let data = ethabi::encode(
|
||||
&[
|
||||
ethabi::Token::Uint(
|
||||
ethabi::Uint::from_big_endian(
|
||||
match self.param0.clone().to_bytes_be() {
|
||||
(num_bigint::Sign::Plus, bytes) => bytes,
|
||||
(num_bigint::Sign::NoSign, bytes) => bytes,
|
||||
(num_bigint::Sign::Minus, _) => {
|
||||
panic!("negative numbers are not supported")
|
||||
}
|
||||
}
|
||||
.as_slice(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
let mut encoded = Vec::with_capacity(4 + data.len());
|
||||
encoded.extend(Self::METHOD_ID);
|
||||
encoded.extend(data);
|
||||
encoded
|
||||
}
|
||||
pub fn output_call(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
Self::output(call.return_data.as_ref())
|
||||
}
|
||||
pub fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address],
|
||||
data.as_ref(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode output data: {:?}", e))?;
|
||||
Ok(
|
||||
values
|
||||
.pop()
|
||||
.expect("one output data should have existed")
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
}
|
||||
pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
match call.input.get(0..4) {
|
||||
Some(signature) => Self::METHOD_ID == signature,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
pub fn call(&self, address: Vec<u8>) -> Option<Vec<u8>> {
|
||||
use substreams_ethereum::pb::eth::rpc;
|
||||
let rpc_calls = rpc::RpcCalls {
|
||||
calls: vec![
|
||||
rpc::RpcCall { to_addr : address, data : self.encode(), }
|
||||
],
|
||||
};
|
||||
let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses;
|
||||
let response = responses
|
||||
.get(0)
|
||||
.expect("one response should have existed");
|
||||
if response.failed {
|
||||
return None;
|
||||
}
|
||||
match Self::output(response.raw.as_ref()) {
|
||||
Ok(data) => Some(data),
|
||||
Err(err) => {
|
||||
use substreams_ethereum::Function;
|
||||
substreams::log::info!(
|
||||
"Call output for function `{}` failed to decode with error: {}",
|
||||
Self::NAME, err
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::Function for AllPairs {
|
||||
const NAME: &'static str = "allPairs";
|
||||
fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
Self::match_call(call)
|
||||
}
|
||||
fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Self::decode(call)
|
||||
}
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.encode()
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::rpc::RPCDecodable<Vec<u8>> for AllPairs {
|
||||
fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
Self::output(data)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct AllPairsLength {}
|
||||
impl AllPairsLength {
|
||||
const METHOD_ID: [u8; 4] = [87u8, 79u8, 43u8, 163u8];
|
||||
pub fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Ok(Self {})
|
||||
}
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let data = ethabi::encode(&[]);
|
||||
let mut encoded = Vec::with_capacity(4 + data.len());
|
||||
encoded.extend(Self::METHOD_ID);
|
||||
encoded.extend(data);
|
||||
encoded
|
||||
}
|
||||
pub fn output_call(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<substreams::scalar::BigInt, String> {
|
||||
Self::output(call.return_data.as_ref())
|
||||
}
|
||||
pub fn output(data: &[u8]) -> Result<substreams::scalar::BigInt, String> {
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Uint(256usize)],
|
||||
data.as_ref(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode output data: {:?}", e))?;
|
||||
Ok({
|
||||
let mut v = [0 as u8; 32];
|
||||
values
|
||||
.pop()
|
||||
.expect("one output data should have existed")
|
||||
.into_uint()
|
||||
.expect(INTERNAL_ERR)
|
||||
.to_big_endian(v.as_mut_slice());
|
||||
substreams::scalar::BigInt::from_unsigned_bytes_be(&v)
|
||||
})
|
||||
}
|
||||
pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
match call.input.get(0..4) {
|
||||
Some(signature) => Self::METHOD_ID == signature,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
pub fn call(&self, address: Vec<u8>) -> Option<substreams::scalar::BigInt> {
|
||||
use substreams_ethereum::pb::eth::rpc;
|
||||
let rpc_calls = rpc::RpcCalls {
|
||||
calls: vec![
|
||||
rpc::RpcCall { to_addr : address, data : self.encode(), }
|
||||
],
|
||||
};
|
||||
let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses;
|
||||
let response = responses
|
||||
.get(0)
|
||||
.expect("one response should have existed");
|
||||
if response.failed {
|
||||
return None;
|
||||
}
|
||||
match Self::output(response.raw.as_ref()) {
|
||||
Ok(data) => Some(data),
|
||||
Err(err) => {
|
||||
use substreams_ethereum::Function;
|
||||
substreams::log::info!(
|
||||
"Call output for function `{}` failed to decode with error: {}",
|
||||
Self::NAME, err
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::Function for AllPairsLength {
|
||||
const NAME: &'static str = "allPairsLength";
|
||||
fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
Self::match_call(call)
|
||||
}
|
||||
fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Self::decode(call)
|
||||
}
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.encode()
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::rpc::RPCDecodable<substreams::scalar::BigInt>
|
||||
for AllPairsLength {
|
||||
fn output(data: &[u8]) -> Result<substreams::scalar::BigInt, String> {
|
||||
Self::output(data)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct CreatePair {
|
||||
pub token_a: Vec<u8>,
|
||||
pub token_b: Vec<u8>,
|
||||
}
|
||||
impl CreatePair {
|
||||
const METHOD_ID: [u8; 4] = [201u8, 198u8, 83u8, 150u8];
|
||||
pub fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
let maybe_data = call.input.get(4..);
|
||||
if maybe_data.is_none() {
|
||||
return Err("no data to decode".to_string());
|
||||
}
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address, ethabi::ParamType::Address],
|
||||
maybe_data.unwrap(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode call.input: {:?}", e))?;
|
||||
values.reverse();
|
||||
Ok(Self {
|
||||
token_a: values
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
token_b: values
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
})
|
||||
}
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let data = ethabi::encode(
|
||||
&[
|
||||
ethabi::Token::Address(
|
||||
ethabi::Address::from_slice(&self.token_a),
|
||||
),
|
||||
ethabi::Token::Address(
|
||||
ethabi::Address::from_slice(&self.token_b),
|
||||
),
|
||||
],
|
||||
);
|
||||
let mut encoded = Vec::with_capacity(4 + data.len());
|
||||
encoded.extend(Self::METHOD_ID);
|
||||
encoded.extend(data);
|
||||
encoded
|
||||
}
|
||||
pub fn output_call(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
Self::output(call.return_data.as_ref())
|
||||
}
|
||||
pub fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address],
|
||||
data.as_ref(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode output data: {:?}", e))?;
|
||||
Ok(
|
||||
values
|
||||
.pop()
|
||||
.expect("one output data should have existed")
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
}
|
||||
pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
match call.input.get(0..4) {
|
||||
Some(signature) => Self::METHOD_ID == signature,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
pub fn call(&self, address: Vec<u8>) -> Option<Vec<u8>> {
|
||||
use substreams_ethereum::pb::eth::rpc;
|
||||
let rpc_calls = rpc::RpcCalls {
|
||||
calls: vec![
|
||||
rpc::RpcCall { to_addr : address, data : self.encode(), }
|
||||
],
|
||||
};
|
||||
let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses;
|
||||
let response = responses
|
||||
.get(0)
|
||||
.expect("one response should have existed");
|
||||
if response.failed {
|
||||
return None;
|
||||
}
|
||||
match Self::output(response.raw.as_ref()) {
|
||||
Ok(data) => Some(data),
|
||||
Err(err) => {
|
||||
use substreams_ethereum::Function;
|
||||
substreams::log::info!(
|
||||
"Call output for function `{}` failed to decode with error: {}",
|
||||
Self::NAME, err
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::Function for CreatePair {
|
||||
const NAME: &'static str = "createPair";
|
||||
fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
Self::match_call(call)
|
||||
}
|
||||
fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Self::decode(call)
|
||||
}
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.encode()
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::rpc::RPCDecodable<Vec<u8>> for CreatePair {
|
||||
fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
Self::output(data)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct FeeTo {}
|
||||
impl FeeTo {
|
||||
const METHOD_ID: [u8; 4] = [1u8, 126u8, 126u8, 88u8];
|
||||
pub fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Ok(Self {})
|
||||
}
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let data = ethabi::encode(&[]);
|
||||
let mut encoded = Vec::with_capacity(4 + data.len());
|
||||
encoded.extend(Self::METHOD_ID);
|
||||
encoded.extend(data);
|
||||
encoded
|
||||
}
|
||||
pub fn output_call(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
Self::output(call.return_data.as_ref())
|
||||
}
|
||||
pub fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address],
|
||||
data.as_ref(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode output data: {:?}", e))?;
|
||||
Ok(
|
||||
values
|
||||
.pop()
|
||||
.expect("one output data should have existed")
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
}
|
||||
pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
match call.input.get(0..4) {
|
||||
Some(signature) => Self::METHOD_ID == signature,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
pub fn call(&self, address: Vec<u8>) -> Option<Vec<u8>> {
|
||||
use substreams_ethereum::pb::eth::rpc;
|
||||
let rpc_calls = rpc::RpcCalls {
|
||||
calls: vec![
|
||||
rpc::RpcCall { to_addr : address, data : self.encode(), }
|
||||
],
|
||||
};
|
||||
let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses;
|
||||
let response = responses
|
||||
.get(0)
|
||||
.expect("one response should have existed");
|
||||
if response.failed {
|
||||
return None;
|
||||
}
|
||||
match Self::output(response.raw.as_ref()) {
|
||||
Ok(data) => Some(data),
|
||||
Err(err) => {
|
||||
use substreams_ethereum::Function;
|
||||
substreams::log::info!(
|
||||
"Call output for function `{}` failed to decode with error: {}",
|
||||
Self::NAME, err
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::Function for FeeTo {
|
||||
const NAME: &'static str = "feeTo";
|
||||
fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
Self::match_call(call)
|
||||
}
|
||||
fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Self::decode(call)
|
||||
}
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.encode()
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::rpc::RPCDecodable<Vec<u8>> for FeeTo {
|
||||
fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
Self::output(data)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct FeeToSetter {}
|
||||
impl FeeToSetter {
|
||||
const METHOD_ID: [u8; 4] = [9u8, 75u8, 116u8, 21u8];
|
||||
pub fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Ok(Self {})
|
||||
}
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let data = ethabi::encode(&[]);
|
||||
let mut encoded = Vec::with_capacity(4 + data.len());
|
||||
encoded.extend(Self::METHOD_ID);
|
||||
encoded.extend(data);
|
||||
encoded
|
||||
}
|
||||
pub fn output_call(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
Self::output(call.return_data.as_ref())
|
||||
}
|
||||
pub fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address],
|
||||
data.as_ref(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode output data: {:?}", e))?;
|
||||
Ok(
|
||||
values
|
||||
.pop()
|
||||
.expect("one output data should have existed")
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
}
|
||||
pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
match call.input.get(0..4) {
|
||||
Some(signature) => Self::METHOD_ID == signature,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
pub fn call(&self, address: Vec<u8>) -> Option<Vec<u8>> {
|
||||
use substreams_ethereum::pb::eth::rpc;
|
||||
let rpc_calls = rpc::RpcCalls {
|
||||
calls: vec![
|
||||
rpc::RpcCall { to_addr : address, data : self.encode(), }
|
||||
],
|
||||
};
|
||||
let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses;
|
||||
let response = responses
|
||||
.get(0)
|
||||
.expect("one response should have existed");
|
||||
if response.failed {
|
||||
return None;
|
||||
}
|
||||
match Self::output(response.raw.as_ref()) {
|
||||
Ok(data) => Some(data),
|
||||
Err(err) => {
|
||||
use substreams_ethereum::Function;
|
||||
substreams::log::info!(
|
||||
"Call output for function `{}` failed to decode with error: {}",
|
||||
Self::NAME, err
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::Function for FeeToSetter {
|
||||
const NAME: &'static str = "feeToSetter";
|
||||
fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
Self::match_call(call)
|
||||
}
|
||||
fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Self::decode(call)
|
||||
}
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.encode()
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::rpc::RPCDecodable<Vec<u8>> for FeeToSetter {
|
||||
fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
Self::output(data)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct GetPair {
|
||||
pub param0: Vec<u8>,
|
||||
pub param1: Vec<u8>,
|
||||
}
|
||||
impl GetPair {
|
||||
const METHOD_ID: [u8; 4] = [230u8, 164u8, 57u8, 5u8];
|
||||
pub fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
let maybe_data = call.input.get(4..);
|
||||
if maybe_data.is_none() {
|
||||
return Err("no data to decode".to_string());
|
||||
}
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address, ethabi::ParamType::Address],
|
||||
maybe_data.unwrap(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode call.input: {:?}", e))?;
|
||||
values.reverse();
|
||||
Ok(Self {
|
||||
param0: values
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
param1: values
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
})
|
||||
}
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let data = ethabi::encode(
|
||||
&[
|
||||
ethabi::Token::Address(
|
||||
ethabi::Address::from_slice(&self.param0),
|
||||
),
|
||||
ethabi::Token::Address(ethabi::Address::from_slice(&self.param1)),
|
||||
],
|
||||
);
|
||||
let mut encoded = Vec::with_capacity(4 + data.len());
|
||||
encoded.extend(Self::METHOD_ID);
|
||||
encoded.extend(data);
|
||||
encoded
|
||||
}
|
||||
pub fn output_call(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
Self::output(call.return_data.as_ref())
|
||||
}
|
||||
pub fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address],
|
||||
data.as_ref(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode output data: {:?}", e))?;
|
||||
Ok(
|
||||
values
|
||||
.pop()
|
||||
.expect("one output data should have existed")
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
}
|
||||
pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
match call.input.get(0..4) {
|
||||
Some(signature) => Self::METHOD_ID == signature,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
pub fn call(&self, address: Vec<u8>) -> Option<Vec<u8>> {
|
||||
use substreams_ethereum::pb::eth::rpc;
|
||||
let rpc_calls = rpc::RpcCalls {
|
||||
calls: vec![
|
||||
rpc::RpcCall { to_addr : address, data : self.encode(), }
|
||||
],
|
||||
};
|
||||
let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses;
|
||||
let response = responses
|
||||
.get(0)
|
||||
.expect("one response should have existed");
|
||||
if response.failed {
|
||||
return None;
|
||||
}
|
||||
match Self::output(response.raw.as_ref()) {
|
||||
Ok(data) => Some(data),
|
||||
Err(err) => {
|
||||
use substreams_ethereum::Function;
|
||||
substreams::log::info!(
|
||||
"Call output for function `{}` failed to decode with error: {}",
|
||||
Self::NAME, err
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::Function for GetPair {
|
||||
const NAME: &'static str = "getPair";
|
||||
fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
Self::match_call(call)
|
||||
}
|
||||
fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Self::decode(call)
|
||||
}
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.encode()
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::rpc::RPCDecodable<Vec<u8>> for GetPair {
|
||||
fn output(data: &[u8]) -> Result<Vec<u8>, String> {
|
||||
Self::output(data)
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct SetFeeTo {
|
||||
pub fee_to: Vec<u8>,
|
||||
}
|
||||
impl SetFeeTo {
|
||||
const METHOD_ID: [u8; 4] = [244u8, 105u8, 1u8, 237u8];
|
||||
pub fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
let maybe_data = call.input.get(4..);
|
||||
if maybe_data.is_none() {
|
||||
return Err("no data to decode".to_string());
|
||||
}
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address],
|
||||
maybe_data.unwrap(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode call.input: {:?}", e))?;
|
||||
values.reverse();
|
||||
Ok(Self {
|
||||
fee_to: values
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
})
|
||||
}
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let data = ethabi::encode(
|
||||
&[ethabi::Token::Address(ethabi::Address::from_slice(&self.fee_to))],
|
||||
);
|
||||
let mut encoded = Vec::with_capacity(4 + data.len());
|
||||
encoded.extend(Self::METHOD_ID);
|
||||
encoded.extend(data);
|
||||
encoded
|
||||
}
|
||||
pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
match call.input.get(0..4) {
|
||||
Some(signature) => Self::METHOD_ID == signature,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::Function for SetFeeTo {
|
||||
const NAME: &'static str = "setFeeTo";
|
||||
fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
Self::match_call(call)
|
||||
}
|
||||
fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Self::decode(call)
|
||||
}
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.encode()
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct SetFeeToSetter {
|
||||
pub fee_to_setter: Vec<u8>,
|
||||
}
|
||||
impl SetFeeToSetter {
|
||||
const METHOD_ID: [u8; 4] = [162u8, 231u8, 74u8, 246u8];
|
||||
pub fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
let maybe_data = call.input.get(4..);
|
||||
if maybe_data.is_none() {
|
||||
return Err("no data to decode".to_string());
|
||||
}
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address],
|
||||
maybe_data.unwrap(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode call.input: {:?}", e))?;
|
||||
values.reverse();
|
||||
Ok(Self {
|
||||
fee_to_setter: values
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
})
|
||||
}
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
let data = ethabi::encode(
|
||||
&[
|
||||
ethabi::Token::Address(
|
||||
ethabi::Address::from_slice(&self.fee_to_setter),
|
||||
),
|
||||
],
|
||||
);
|
||||
let mut encoded = Vec::with_capacity(4 + data.len());
|
||||
encoded.extend(Self::METHOD_ID);
|
||||
encoded.extend(data);
|
||||
encoded
|
||||
}
|
||||
pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
match call.input.get(0..4) {
|
||||
Some(signature) => Self::METHOD_ID == signature,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::Function for SetFeeToSetter {
|
||||
const NAME: &'static str = "setFeeToSetter";
|
||||
fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool {
|
||||
Self::match_call(call)
|
||||
}
|
||||
fn decode(
|
||||
call: &substreams_ethereum::pb::eth::v2::Call,
|
||||
) -> Result<Self, String> {
|
||||
Self::decode(call)
|
||||
}
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
self.encode()
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Contract's events.
|
||||
#[allow(dead_code, unused_imports, unused_variables)]
|
||||
pub mod events {
|
||||
use super::INTERNAL_ERR;
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct PairCreated {
|
||||
pub token0: Vec<u8>,
|
||||
pub token1: Vec<u8>,
|
||||
pub pair: Vec<u8>,
|
||||
pub param3: substreams::scalar::BigInt,
|
||||
}
|
||||
impl PairCreated {
|
||||
const TOPIC_ID: [u8; 32] = [
|
||||
13u8,
|
||||
54u8,
|
||||
72u8,
|
||||
189u8,
|
||||
15u8,
|
||||
107u8,
|
||||
168u8,
|
||||
1u8,
|
||||
52u8,
|
||||
163u8,
|
||||
59u8,
|
||||
169u8,
|
||||
39u8,
|
||||
90u8,
|
||||
197u8,
|
||||
133u8,
|
||||
217u8,
|
||||
211u8,
|
||||
21u8,
|
||||
240u8,
|
||||
173u8,
|
||||
131u8,
|
||||
85u8,
|
||||
205u8,
|
||||
222u8,
|
||||
253u8,
|
||||
227u8,
|
||||
26u8,
|
||||
250u8,
|
||||
40u8,
|
||||
208u8,
|
||||
233u8,
|
||||
];
|
||||
pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool {
|
||||
if log.topics.len() != 3usize {
|
||||
return false;
|
||||
}
|
||||
if log.data.len() != 64usize {
|
||||
return false;
|
||||
}
|
||||
return log.topics.get(0).expect("bounds already checked").as_ref()
|
||||
== Self::TOPIC_ID;
|
||||
}
|
||||
pub fn decode(
|
||||
log: &substreams_ethereum::pb::eth::v2::Log,
|
||||
) -> Result<Self, String> {
|
||||
let mut values = ethabi::decode(
|
||||
&[ethabi::ParamType::Address, ethabi::ParamType::Uint(256usize)],
|
||||
log.data.as_ref(),
|
||||
)
|
||||
.map_err(|e| format!("unable to decode log.data: {:?}", e))?;
|
||||
values.reverse();
|
||||
Ok(Self {
|
||||
token0: ethabi::decode(
|
||||
&[ethabi::ParamType::Address],
|
||||
log.topics[1usize].as_ref(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
"unable to decode param 'token0' from topic of type 'address': {:?}",
|
||||
e
|
||||
)
|
||||
})?
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
token1: ethabi::decode(
|
||||
&[ethabi::ParamType::Address],
|
||||
log.topics[2usize].as_ref(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
"unable to decode param 'token1' from topic of type 'address': {:?}",
|
||||
e
|
||||
)
|
||||
})?
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
pair: values
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_address()
|
||||
.expect(INTERNAL_ERR)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
param3: {
|
||||
let mut v = [0 as u8; 32];
|
||||
values
|
||||
.pop()
|
||||
.expect(INTERNAL_ERR)
|
||||
.into_uint()
|
||||
.expect(INTERNAL_ERR)
|
||||
.to_big_endian(v.as_mut_slice());
|
||||
substreams::scalar::BigInt::from_unsigned_bytes_be(&v)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
impl substreams_ethereum::Event for PairCreated {
|
||||
const NAME: &'static str = "PairCreated";
|
||||
fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool {
|
||||
Self::match_log(log)
|
||||
}
|
||||
fn decode(
|
||||
log: &substreams_ethereum::pb::eth::v2::Log,
|
||||
) -> Result<Self, String> {
|
||||
Self::decode(log)
|
||||
}
|
||||
}
|
||||
}
|
||||
4
substreams/ethereum-uniswap-v2/src/abi/mod.rs
Normal file
4
substreams/ethereum-uniswap-v2/src/abi/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#![allow(clippy::all, clippy::pedantic, clippy::nursery)]
|
||||
|
||||
pub mod factory;
|
||||
pub mod pool;
|
||||
3554
substreams/ethereum-uniswap-v2/src/abi/pool.rs
Normal file
3554
substreams/ethereum-uniswap-v2/src/abi/pool.rs
Normal file
File diff suppressed because it is too large
Load Diff
10
substreams/ethereum-uniswap-v2/src/lib.rs
Normal file
10
substreams/ethereum-uniswap-v2/src/lib.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
#![allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
|
||||
mod abi;
|
||||
mod modules;
|
||||
mod pb;
|
||||
|
||||
pub use modules::*;
|
||||
|
||||
mod store_key;
|
||||
mod traits;
|
||||
@@ -0,0 +1,99 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use ethabi::ethereum_types::Address;
|
||||
use serde::Deserialize;
|
||||
use substreams::prelude::BigInt;
|
||||
use substreams_ethereum::pb::eth::v2::{self as eth};
|
||||
|
||||
use substreams_helper::{event_handler::EventHandler, hex::Hexable};
|
||||
|
||||
use crate::{
|
||||
abi::factory::events::PairCreated,
|
||||
pb::tycho::evm::v1::{
|
||||
Attribute, Block, BlockChanges, ChangeType, EntityChanges, FinancialType,
|
||||
ImplementationType, ProtocolComponent, ProtocolType, Transaction, TransactionChanges,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Params {
|
||||
factory_address: String,
|
||||
protocol_type_name: String,
|
||||
}
|
||||
|
||||
#[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 params: Params = serde_qs::from_str(params.as_str()).expect("Unable to deserialize params");
|
||||
|
||||
get_pools(&block, &mut new_pools, ¶ms);
|
||||
|
||||
let tycho_block: Block = block.into();
|
||||
|
||||
Ok(BlockChanges { block: Some(tycho_block), changes: new_pools })
|
||||
}
|
||||
|
||||
fn get_pools(block: ð::Block, new_pools: &mut Vec<TransactionChanges>, params: &Params) {
|
||||
// Extract new pools from PairCreated events
|
||||
let mut on_pair_created = |event: PairCreated, _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.pair.to_hex(),
|
||||
attributes: vec![
|
||||
Attribute {
|
||||
name: "reserve0".to_string(),
|
||||
value: BigInt::from(0).to_signed_bytes_le(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "reserve1".to_string(),
|
||||
value: BigInt::from(0).to_signed_bytes_le(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
],
|
||||
}],
|
||||
component_changes: vec![ProtocolComponent {
|
||||
id: event.pair.to_hex(),
|
||||
tokens: vec![event.token0, event.token1],
|
||||
contracts: vec![],
|
||||
static_att: vec![
|
||||
// Trading Fee is hardcoded to 0.3%, saved as int in bps (basis points)
|
||||
Attribute {
|
||||
name: "fee".to_string(),
|
||||
value: BigInt::from(30).to_signed_bytes_le(),
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
Attribute {
|
||||
name: "pool_address".to_string(),
|
||||
value: event.pair,
|
||||
change: ChangeType::Creation.into(),
|
||||
},
|
||||
],
|
||||
change: i32::from(ChangeType::Creation),
|
||||
protocol_type: Some(ProtocolType {
|
||||
name: params.protocol_type_name.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(¶ms.factory_address).unwrap()]);
|
||||
|
||||
eh.on::<PairCreated, _>(&mut on_pair_created);
|
||||
eh.handle_events();
|
||||
}
|
||||
25
substreams/ethereum-uniswap-v2/src/modules/2_store_pools.rs
Normal file
25
substreams/ethereum-uniswap-v2/src/modules/2_store_pools.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use substreams::store::{StoreNew, StoreSetIfNotExists, StoreSetIfNotExistsProto};
|
||||
|
||||
use crate::{
|
||||
pb::tycho::evm::v1::{BlockChanges, ProtocolComponent},
|
||||
store_key::StoreKey,
|
||||
};
|
||||
|
||||
#[substreams::handlers::store]
|
||||
pub fn store_pools(
|
||||
pools_created: BlockChanges,
|
||||
store: StoreSetIfNotExistsProto<ProtocolComponent>,
|
||||
) {
|
||||
// Store pools. Required so the next steps can match any event to a known pool by their address
|
||||
|
||||
for change in pools_created.changes {
|
||||
for new_protocol_component in change.component_changes {
|
||||
// Use ordinal 0 because the address should be unique, so ordering doesn't matter.
|
||||
store.set_if_not_exists(
|
||||
0,
|
||||
StoreKey::Pool.get_unique_pool_key(&new_protocol_component.id),
|
||||
&new_protocol_component,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
232
substreams/ethereum-uniswap-v2/src/modules/3_map_pool_events.rs
Normal file
232
substreams/ethereum-uniswap-v2/src/modules/3_map_pool_events.rs
Normal file
@@ -0,0 +1,232 @@
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
use substreams::store::{StoreGet, StoreGetProto};
|
||||
use substreams_ethereum::pb::eth::v2::{self as eth};
|
||||
|
||||
use substreams_helper::{event_handler::EventHandler, hex::Hexable};
|
||||
|
||||
use crate::{
|
||||
abi::pool::events::Sync,
|
||||
pb::tycho::evm::{
|
||||
v1,
|
||||
v1::{
|
||||
Attribute, BalanceChange, BlockChanges, ChangeType, EntityChanges, ProtocolComponent,
|
||||
TransactionChanges,
|
||||
},
|
||||
},
|
||||
store_key::StoreKey,
|
||||
traits::PoolAddresser,
|
||||
};
|
||||
|
||||
// Auxiliary struct to serve as a key for the HashMaps.
|
||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
struct ComponentKey<T> {
|
||||
component_id: String,
|
||||
name: T,
|
||||
}
|
||||
|
||||
impl<T> ComponentKey<T> {
|
||||
fn new(component_id: String, name: T) -> Self {
|
||||
ComponentKey { component_id, name }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct PartialChanges {
|
||||
transaction: v1::Transaction,
|
||||
entity_changes: HashMap<ComponentKey<String>, Attribute>,
|
||||
balance_changes: HashMap<ComponentKey<Vec<u8>>, BalanceChange>,
|
||||
}
|
||||
|
||||
impl PartialChanges {
|
||||
// Consolidate the entity changes into a vector of EntityChanges. Initially, the entity changes
|
||||
// are in a map to prevent duplicates. For each transaction, we need to have only one final
|
||||
// state change, per state. Example:
|
||||
// If we have two sync events for the same pool (in the same tx), we need to have only one final
|
||||
// state change for the reserves. This will be the last sync event, as it is the final state
|
||||
// of the pool after the transaction.
|
||||
fn consolidate_entity_changes(self) -> Vec<EntityChanges> {
|
||||
self.entity_changes
|
||||
.into_iter()
|
||||
.map(|(key, attribute)| (key.component_id, attribute))
|
||||
.into_group_map()
|
||||
.into_iter()
|
||||
.map(|(component_id, attributes)| EntityChanges { component_id, attributes })
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[substreams::handlers::map]
|
||||
pub fn map_pool_events(
|
||||
block: eth::Block,
|
||||
block_entity_changes: BlockChanges,
|
||||
pools_store: StoreGetProto<ProtocolComponent>,
|
||||
) -> Result<BlockChanges, substreams::errors::Error> {
|
||||
// Sync event is sufficient for our use-case. Since it's emitted on every reserve-altering
|
||||
// function call, we can use it as the only event to update the reserves of a pool.
|
||||
let mut block_entity_changes = block_entity_changes;
|
||||
let mut tx_changes: HashMap<Vec<u8>, PartialChanges> = HashMap::new();
|
||||
|
||||
handle_sync(&block, &mut tx_changes, &pools_store);
|
||||
merge_block(&mut tx_changes, &mut block_entity_changes);
|
||||
|
||||
Ok(block_entity_changes)
|
||||
}
|
||||
|
||||
/// Handle the sync events and update the reserves of the pools.
|
||||
///
|
||||
/// This function is called for each block, and it will handle the sync events for each transaction.
|
||||
/// On UniswapV2, Sync events are emitted on every reserve-altering function call, so we can use
|
||||
/// only this event to keep track of the pool state.
|
||||
///
|
||||
/// This function also relies on an intermediate HashMap to store the changes for each transaction.
|
||||
/// This is necessary because we need to consolidate the changes for each transaction before adding
|
||||
/// them to the block_entity_changes. This HashMap prevents us from having duplicate changes for the
|
||||
/// same pool and token. See the PartialChanges struct for more details.
|
||||
fn handle_sync(
|
||||
block: ð::Block,
|
||||
tx_changes: &mut HashMap<Vec<u8>, PartialChanges>,
|
||||
store: &StoreGetProto<ProtocolComponent>,
|
||||
) {
|
||||
let mut on_sync = |event: Sync, _tx: ð::TransactionTrace, _log: ð::Log| {
|
||||
let pool_address_hex = _log.address.to_hex();
|
||||
|
||||
let pool =
|
||||
store.must_get_last(StoreKey::Pool.get_unique_pool_key(pool_address_hex.as_str()));
|
||||
// Convert reserves to bytes
|
||||
let reserves_bytes = [event.reserve0, event.reserve1];
|
||||
|
||||
let tx_change = tx_changes
|
||||
.entry(_tx.hash.clone())
|
||||
.or_insert_with(|| PartialChanges {
|
||||
transaction: _tx.into(),
|
||||
entity_changes: HashMap::new(),
|
||||
balance_changes: HashMap::new(),
|
||||
});
|
||||
|
||||
for (i, reserve_bytes) in reserves_bytes.iter().enumerate() {
|
||||
let attribute_name = format!("reserve{}", i);
|
||||
// By using a HashMap, we can overwrite the previous value of the reserve attribute if
|
||||
// it is for the same pool and the same attribute name (reserves).
|
||||
tx_change.entity_changes.insert(
|
||||
ComponentKey::new(pool_address_hex.clone(), attribute_name.clone()),
|
||||
Attribute {
|
||||
name: attribute_name,
|
||||
value: reserve_bytes
|
||||
.clone()
|
||||
.to_signed_bytes_le(), //TODO: Unify bytes encoding (either be or le)
|
||||
change: ChangeType::Update.into(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Update balance changes for each token
|
||||
for (index, token) in pool.tokens.iter().enumerate() {
|
||||
let balance = &reserves_bytes[index];
|
||||
// HashMap also prevents having duplicate balance changes for the same pool and token.
|
||||
tx_change.balance_changes.insert(
|
||||
ComponentKey::new(pool_address_hex.clone(), token.clone()),
|
||||
BalanceChange {
|
||||
token: token.clone(),
|
||||
balance: balance.clone().to_signed_bytes_be(),
|
||||
component_id: pool_address_hex.as_bytes().to_vec(),
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let mut eh = EventHandler::new(block);
|
||||
// Filter the sync events by the pool address, to make sure we don't process events for other
|
||||
// Protocols that use the same event signature.
|
||||
eh.filter_by_address(PoolAddresser { store });
|
||||
eh.on::<Sync, _>(&mut on_sync);
|
||||
eh.handle_events();
|
||||
}
|
||||
|
||||
/// Merge the changes from the sync events with the create_pool events previously mapped on
|
||||
/// block_entity_changes.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - tx_changes: HashMap with the changes for each transaction. This is the same HashMap used in
|
||||
/// handle_sync
|
||||
/// - block_entity_changes: The BlockChanges struct that will be updated with the changes from the
|
||||
/// sync events.
|
||||
/// This HashMap comes pre-filled with the changes for the create_pool events, mapped in
|
||||
/// 1_map_pool_created.
|
||||
///
|
||||
/// This function is called after the handle_sync function, and it is expected that
|
||||
/// block_entity_changes will be complete after this function ends.
|
||||
fn merge_block(
|
||||
tx_changes: &mut HashMap<Vec<u8>, PartialChanges>,
|
||||
block_entity_changes: &mut BlockChanges,
|
||||
) {
|
||||
let mut tx_entity_changes_map = HashMap::new();
|
||||
|
||||
// Add created pools to the tx_changes_map
|
||||
for change in block_entity_changes
|
||||
.changes
|
||||
.clone()
|
||||
.into_iter()
|
||||
{
|
||||
let transaction = change.tx.as_ref().unwrap();
|
||||
tx_entity_changes_map
|
||||
.entry(transaction.hash.clone())
|
||||
.and_modify(|c: &mut TransactionChanges| {
|
||||
c.component_changes
|
||||
.extend(change.component_changes.clone());
|
||||
c.entity_changes
|
||||
.extend(change.entity_changes.clone());
|
||||
})
|
||||
.or_insert(change);
|
||||
}
|
||||
|
||||
// First, iterate through the previously created transactions, extracted from the
|
||||
// map_pool_created step. If there are sync events for this transaction, add them to the
|
||||
// block_entity_changes and the corresponding balance changes.
|
||||
for change in tx_entity_changes_map.values_mut() {
|
||||
let tx = change
|
||||
.clone()
|
||||
.tx
|
||||
.expect("Transaction not found")
|
||||
.clone();
|
||||
|
||||
// If there are sync events for this transaction, add them to the block_entity_changes
|
||||
if let Some(partial_changes) = tx_changes.remove(&tx.hash) {
|
||||
change.entity_changes = partial_changes
|
||||
.clone()
|
||||
.consolidate_entity_changes();
|
||||
change.balance_changes = partial_changes
|
||||
.balance_changes
|
||||
.into_values()
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any transactions left in the tx_changes, it means that they are transactions
|
||||
// that changed the state of the pools, but were not included in the block_entity_changes.
|
||||
// This happens for every regular transaction that does not actually create a pool. By the
|
||||
// end of this function, we expect block_entity_changes to be up-to-date with the changes
|
||||
// for all sync and new_pools in the block.
|
||||
for partial_changes in tx_changes.values() {
|
||||
tx_entity_changes_map.insert(
|
||||
partial_changes.transaction.hash.clone(),
|
||||
TransactionChanges {
|
||||
tx: Some(partial_changes.transaction.clone()),
|
||||
contract_changes: vec![],
|
||||
entity_changes: partial_changes
|
||||
.clone()
|
||||
.consolidate_entity_changes(),
|
||||
balance_changes: partial_changes
|
||||
.balance_changes
|
||||
.clone()
|
||||
.into_values()
|
||||
.collect(),
|
||||
component_changes: vec![],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
block_entity_changes.changes = tx_entity_changes_map
|
||||
.into_values()
|
||||
.collect();
|
||||
}
|
||||
11
substreams/ethereum-uniswap-v2/src/modules/mod.rs
Normal file
11
substreams/ethereum-uniswap-v2/src/modules/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
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_pool_events.rs"]
|
||||
mod map_pool_events;
|
||||
17
substreams/ethereum-uniswap-v2/src/pb/mod.rs
Normal file
17
substreams/ethereum-uniswap-v2/src/pb/mod.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
// @generated
|
||||
pub mod tycho {
|
||||
pub mod evm {
|
||||
pub mod uniswap {
|
||||
// @@protoc_insertion_point(attribute:tycho.evm.uniswap.v2)
|
||||
pub mod v2 {
|
||||
include!("tycho.evm.uniswap.v2.rs");
|
||||
// @@protoc_insertion_point(tycho.evm.uniswap.v2)
|
||||
}
|
||||
}
|
||||
// @@protoc_insertion_point(attribute:tycho.evm.v1)
|
||||
pub mod v1 {
|
||||
include!("tycho.evm.v1.rs");
|
||||
// @@protoc_insertion_point(tycho.evm.v1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// @generated
|
||||
#[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(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>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Events {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub events: ::prost::alloc::vec::Vec<Event>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Event {
|
||||
#[prost(string, tag="100")]
|
||||
pub hash: ::prost::alloc::string::String,
|
||||
#[prost(uint32, tag="101")]
|
||||
pub log_index: u32,
|
||||
#[prost(uint64, tag="102")]
|
||||
pub log_ordinal: u64,
|
||||
#[prost(string, tag="103")]
|
||||
pub to: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="104")]
|
||||
pub from: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag="105")]
|
||||
pub block_number: u64,
|
||||
#[prost(uint64, tag="106")]
|
||||
pub timestamp: u64,
|
||||
#[prost(string, tag="107")]
|
||||
pub pool: ::prost::alloc::string::String,
|
||||
#[prost(oneof="event::Type", tags="10, 20, 30, 40")]
|
||||
pub r#type: ::core::option::Option<event::Type>,
|
||||
}
|
||||
/// Nested message and enum types in `Event`.
|
||||
pub mod event {
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Type {
|
||||
#[prost(message, tag="10")]
|
||||
DepositType(super::DepositEvent),
|
||||
#[prost(message, tag="20")]
|
||||
WithdrawType(super::WithdrawEvent),
|
||||
#[prost(message, tag="30")]
|
||||
SyncType(super::SyncEvent),
|
||||
#[prost(message, tag="40")]
|
||||
SwapType(super::SwapEvent),
|
||||
}
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct DepositEvent {
|
||||
#[prost(string, repeated, tag="1")]
|
||||
pub input_token_amounts: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||
#[prost(string, optional, tag="2")]
|
||||
pub output_token_amount: ::core::option::Option<::prost::alloc::string::String>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct WithdrawEvent {
|
||||
#[prost(string, repeated, tag="1")]
|
||||
pub input_token_amounts: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||
#[prost(string, optional, tag="2")]
|
||||
pub output_token_amount: ::core::option::Option<::prost::alloc::string::String>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SyncEvent {
|
||||
#[prost(string, tag="1")]
|
||||
pub reserve0: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub reserve1: ::prost::alloc::string::String,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SwapEvent {
|
||||
#[prost(string, tag="1")]
|
||||
pub token_in: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="2")]
|
||||
pub amount_in: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="3")]
|
||||
pub token_out: ::prost::alloc::string::String,
|
||||
#[prost(string, tag="4")]
|
||||
pub amount_out: ::prost::alloc::string::String,
|
||||
}
|
||||
// @@protoc_insertion_point(module)
|
||||
307
substreams/ethereum-uniswap-v2/src/pb/tycho.evm.v1.rs
Normal file
307
substreams/ethereum-uniswap-v2/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)
|
||||
16
substreams/ethereum-uniswap-v2/src/store_key.rs
Normal file
16
substreams/ethereum-uniswap-v2/src/store_key.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
#[derive(Clone)]
|
||||
pub enum StoreKey {
|
||||
Pool,
|
||||
}
|
||||
|
||||
impl StoreKey {
|
||||
pub fn get_unique_pool_key(&self, key: &str) -> String {
|
||||
format!("{}:{}", self.unique_id(), key)
|
||||
}
|
||||
|
||||
pub fn unique_id(&self) -> String {
|
||||
match self {
|
||||
StoreKey::Pool => "Pool".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
51
substreams/ethereum-uniswap-v2/src/traits.rs
Normal file
51
substreams/ethereum-uniswap-v2/src/traits.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use ethabi::ethereum_types::Address;
|
||||
use substreams::store::{StoreGet, StoreGetProto};
|
||||
use substreams_ethereum::pb::eth::v2::{self as eth};
|
||||
|
||||
use substreams_helper::{common::HasAddresser, hex::Hexable};
|
||||
|
||||
use crate::{
|
||||
pb::tycho::evm::v1::{Block, ProtocolComponent, Transaction},
|
||||
store_key::StoreKey,
|
||||
};
|
||||
|
||||
pub struct PoolAddresser<'a> {
|
||||
pub store: &'a StoreGetProto<ProtocolComponent>,
|
||||
}
|
||||
|
||||
impl<'a> HasAddresser for PoolAddresser<'a> {
|
||||
fn has_address(&self, key: Address) -> bool {
|
||||
let pool = self
|
||||
.store
|
||||
.get_last(StoreKey::Pool.get_unique_pool_key(&key.to_hex()));
|
||||
|
||||
pool.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
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