Merge pull request #31 from propeller-heads/feat/ethereum-curve

Curve Substreams
This commit is contained in:
Zizou
2024-06-14 19:52:21 +02:00
committed by GitHub
47 changed files with 67251 additions and 7 deletions

2
.gitignore vendored
View File

@@ -13,3 +13,5 @@ target/
*.log
substreams/ethereum-template/Cargo.lock
.DS_Store

47
substreams/Cargo.lock generated
View File

@@ -227,6 +227,27 @@ dependencies = [
"tycho-substreams",
]
[[package]]
name = "ethereum-curve"
version = "0.1.0"
dependencies = [
"anyhow",
"bytes",
"ethabi 18.0.0",
"getrandom",
"hex",
"hex-literal 0.4.1",
"itertools 0.13.0",
"num-bigint",
"prost 0.11.9",
"prost-types 0.12.3",
"serde",
"serde_qs",
"substreams",
"substreams-ethereum",
"tycho-substreams",
]
[[package]]
name = "ethereum-types"
version = "0.13.1"
@@ -432,6 +453,15 @@ dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.10"
@@ -553,6 +583,12 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "petgraph"
version = "0.6.4"
@@ -850,6 +886,17 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_qs"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6"
dependencies = [
"percent-encoding",
"serde",
"thiserror",
]
[[package]]
name = "sha3"
version = "0.10.8"

View File

@@ -1,8 +1,5 @@
[workspace]
members = [
"ethereum-balancer",
"crates/tycho-substreams",
]
members = ["ethereum-balancer", "ethereum-curve", "crates/tycho-substreams"]
resolver = "2"
@@ -14,9 +11,9 @@ prost-types = "0.12.3"
hex-literal = "0.4.1"
hex = "0.4.3"
ethabi = "18.0.0"
tycho-substreams = {path ="crates/tycho-substreams"}
tycho-substreams = { path = "crates/tycho-substreams" }
[profile.release]
lto = true
opt-level = 's'
strip = "debuginfo"
strip = "debuginfo"

View File

@@ -34,6 +34,7 @@ impl SerializableVecBigInt for Vec<BigInt> {
/// - Weighted Pool Factories
/// - Linear Pool Factories
/// - Stable Pool Factories
///
/// (Balancer does have a bit more (esp. in the deprecated section) that could be implemented as
/// desired.)
/// We use the specific ABIs to decode both the log event and corresponding call to gather

1269
substreams/ethereum-curve/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
[package]
name = "ethereum-curve"
version = "0.1.0"
edition = "2021"
[lib]
name = "ethereum_curve"
crate-type = ["cdylib"]
[dependencies]
substreams.workspace = true
substreams-ethereum.workspace = true
prost.workspace = true
prost-types.workspace = true
hex-literal.workspace = true
ethabi.workspace = true
hex.workspace = true
bytes = "1.5.0"
anyhow = "1.0.75"
num-bigint = "0.4.4"
tycho-substreams.workspace = true
serde = { version = "1.0", features = ["derive"] }
serde_qs = "0.13.0"
itertools = "0.13.0"
[build-dependencies]
anyhow = "1"
substreams-ethereum = "0.9"
# Required so that ethabi > ethereum-types build correctly under wasm32-unknown-unknown
[target.wasm32-unknown-unknown.dependencies]
getrandom = { version = "0.2", features = ["custom"] }

View File

@@ -0,0 +1,21 @@
# Instructions
The run command for our substream is a little different here due to the inclusion of the dynamic parameters for manually admitted pools.
This command will add extra parameters to the `map_components` module via the `python params.py` script. This embeds directly in the bash/zsh compatible command here. If `python` is not ideal, the script can be easily converted into `bash` but it would require the `jq` executable (I've used AI to convert it just fine in testing).
```bash
$ substreams run -e mainnet.eth.streamingfast.io:443 substreams.yaml map_protocol_changes --start-block 11507454 --stop-block +100 -p map_components=`python params.py`
```
## `params.json`
This json file is a top-level array containing objects that describe a specific `ProtocolComponent`. Each object contains the following fields:
- `name`: Just for documentation purposes
- `address`: The **lowercase** address of the component
- `tx_hash`: The hash of the transaction where the component was emitted
- `tokens`: A list of token addresses ordered in the exact same way as the Pool
- `attributes`: A nested object of key to value that represents the static attributes of the component.
Please see the included 3 examples for `3pool`, `steth`, and `tricrypto2`.

View File

@@ -0,0 +1,22 @@
# ABIs
`get_abis.py` is a simple python script using the etherscan API (free plan) to gather ABIs for all of the contracts we are tracking!
We then can define all of the abis via `substreams_ethereum::Abigen::new` in our `build.rs`.
## Recommendation
It would be apt to convert (maybe through copilot) the python code into the `build.rs` file and then automate the `Abigen` functionality.
## Usage
Requires `python 3.8+`,
```bash
cd abi
python get_abis.py
```
This will populate the files in the `abi` folder.
When the `build.rs` file runs (when `rust-analyzer` activates or `cargo build` is manually ran), Abigen will generate new rust src files from the abis in the `src/abi` folder.

View File

@@ -0,0 +1,635 @@
[
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "coins",
"type": "address[2]"
},
{
"indexed": false,
"name": "A",
"type": "uint256"
},
{
"indexed": false,
"name": "gamma",
"type": "uint256"
},
{
"indexed": false,
"name": "mid_fee",
"type": "uint256"
},
{
"indexed": false,
"name": "out_fee",
"type": "uint256"
},
{
"indexed": false,
"name": "allowed_extra_profit",
"type": "uint256"
},
{
"indexed": false,
"name": "fee_gamma",
"type": "uint256"
},
{
"indexed": false,
"name": "adjustment_step",
"type": "uint256"
},
{
"indexed": false,
"name": "admin_fee",
"type": "uint256"
},
{
"indexed": false,
"name": "ma_half_time",
"type": "uint256"
},
{
"indexed": false,
"name": "initial_price",
"type": "uint256"
},
{
"indexed": false,
"name": "deployer",
"type": "address"
}
],
"name": "CryptoPoolDeployed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "pool",
"type": "address"
},
{
"indexed": false,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "gauge",
"type": "address"
}
],
"name": "LiquidityGaugeDeployed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "_old_fee_receiver",
"type": "address"
},
{
"indexed": false,
"name": "_new_fee_receiver",
"type": "address"
}
],
"name": "UpdateFeeReceiver",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "_old_pool_implementation",
"type": "address"
},
{
"indexed": false,
"name": "_new_pool_implementation",
"type": "address"
}
],
"name": "UpdatePoolImplementation",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "_old_token_implementation",
"type": "address"
},
{
"indexed": false,
"name": "_new_token_implementation",
"type": "address"
}
],
"name": "UpdateTokenImplementation",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "_old_gauge_implementation",
"type": "address"
},
{
"indexed": false,
"name": "_new_gauge_implementation",
"type": "address"
}
],
"name": "UpdateGaugeImplementation",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "_old_owner",
"type": "address"
},
{
"indexed": false,
"name": "_new_owner",
"type": "address"
}
],
"name": "TransferOwnership",
"type": "event"
},
{
"inputs": [
{
"name": "_fee_receiver",
"type": "address"
},
{
"name": "_pool_implementation",
"type": "address"
},
{
"name": "_token_implementation",
"type": "address"
},
{
"name": "_gauge_implementation",
"type": "address"
},
{
"name": "_weth",
"type": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"name": "_name",
"type": "string"
},
{
"name": "_symbol",
"type": "string"
},
{
"name": "_coins",
"type": "address[2]"
},
{
"name": "A",
"type": "uint256"
},
{
"name": "gamma",
"type": "uint256"
},
{
"name": "mid_fee",
"type": "uint256"
},
{
"name": "out_fee",
"type": "uint256"
},
{
"name": "allowed_extra_profit",
"type": "uint256"
},
{
"name": "fee_gamma",
"type": "uint256"
},
{
"name": "adjustment_step",
"type": "uint256"
},
{
"name": "admin_fee",
"type": "uint256"
},
{
"name": "ma_half_time",
"type": "uint256"
},
{
"name": "initial_price",
"type": "uint256"
}
],
"name": "deploy_pool",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "deploy_gauge",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_fee_receiver",
"type": "address"
}
],
"name": "set_fee_receiver",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_pool_implementation",
"type": "address"
}
],
"name": "set_pool_implementation",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_token_implementation",
"type": "address"
}
],
"name": "set_token_implementation",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_gauge_implementation",
"type": "address"
}
],
"name": "set_gauge_implementation",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_addr",
"type": "address"
}
],
"name": "commit_transfer_ownership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "accept_transfer_ownership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"name": "find_pool_for_coins",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "i",
"type": "uint256"
}
],
"name": "find_pool_for_coins",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_coins",
"outputs": [
{
"name": "",
"type": "address[2]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_decimals",
"outputs": [
{
"name": "",
"type": "uint256[2]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_balances",
"outputs": [
{
"name": "",
"type": "uint256[2]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"name": "get_coin_indices",
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_gauge",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_eth_index",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_token",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "admin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "future_admin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "fee_receiver",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pool_implementation",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "token_implementation",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "gauge_implementation",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pool_count",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"name": "pool_list",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]

View File

@@ -0,0 +1,996 @@
[
{
"name": "BasePoolAdded",
"inputs": [
{
"name": "base_pool",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "PlainPoolDeployed",
"inputs": [
{
"name": "coins",
"type": "address[]",
"indexed": false
},
{
"name": "A",
"type": "uint256",
"indexed": false
},
{
"name": "fee",
"type": "uint256",
"indexed": false
},
{
"name": "deployer",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "MetaPoolDeployed",
"inputs": [
{
"name": "coin",
"type": "address",
"indexed": false
},
{
"name": "base_pool",
"type": "address",
"indexed": false
},
{
"name": "A",
"type": "uint256",
"indexed": false
},
{
"name": "fee",
"type": "uint256",
"indexed": false
},
{
"name": "deployer",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "LiquidityGaugeDeployed",
"inputs": [
{
"name": "pool",
"type": "address",
"indexed": false
},
{
"name": "gauge",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"stateMutability": "nonpayable",
"type": "constructor",
"inputs": [
{
"name": "_fee_receiver",
"type": "address"
},
{
"name": "_owner",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "view",
"type": "function",
"name": "find_pool_for_coins",
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "find_pool_for_coins",
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "i",
"type": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_base_pool",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_n_coins",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_meta_n_coins",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_coins",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address[]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_underlying_coins",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address[]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_decimals",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256[]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_underlying_decimals",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256[]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_metapool_rates",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256[]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_balances",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256[]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_underlying_balances",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256[]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_A",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_fees",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_admin_balances",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256[]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_coin_indices",
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "int128"
},
{
"name": "",
"type": "int128"
},
{
"name": "",
"type": "bool"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_gauge",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_implementation_address",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "is_meta",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "bool"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_pool_asset_types",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint8[]"
}
]
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "deploy_plain_pool",
"inputs": [
{
"name": "_name",
"type": "string"
},
{
"name": "_symbol",
"type": "string"
},
{
"name": "_coins",
"type": "address[]"
},
{
"name": "_A",
"type": "uint256"
},
{
"name": "_fee",
"type": "uint256"
},
{
"name": "_offpeg_fee_multiplier",
"type": "uint256"
},
{
"name": "_ma_exp_time",
"type": "uint256"
},
{
"name": "_implementation_idx",
"type": "uint256"
},
{
"name": "_asset_types",
"type": "uint8[]"
},
{
"name": "_method_ids",
"type": "bytes4[]"
},
{
"name": "_oracles",
"type": "address[]"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "deploy_metapool",
"inputs": [
{
"name": "_base_pool",
"type": "address"
},
{
"name": "_name",
"type": "string"
},
{
"name": "_symbol",
"type": "string"
},
{
"name": "_coin",
"type": "address"
},
{
"name": "_A",
"type": "uint256"
},
{
"name": "_fee",
"type": "uint256"
},
{
"name": "_offpeg_fee_multiplier",
"type": "uint256"
},
{
"name": "_ma_exp_time",
"type": "uint256"
},
{
"name": "_implementation_idx",
"type": "uint256"
},
{
"name": "_asset_type",
"type": "uint8"
},
{
"name": "_method_id",
"type": "bytes4"
},
{
"name": "_oracle",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "deploy_gauge",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "add_base_pool",
"inputs": [
{
"name": "_base_pool",
"type": "address"
},
{
"name": "_base_lp_token",
"type": "address"
},
{
"name": "_asset_types",
"type": "uint8[]"
},
{
"name": "_n_coins",
"type": "uint256"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_pool_implementations",
"inputs": [
{
"name": "_implementation_index",
"type": "uint256"
},
{
"name": "_implementation",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_metapool_implementations",
"inputs": [
{
"name": "_implementation_index",
"type": "uint256"
},
{
"name": "_implementation",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_math_implementation",
"inputs": [
{
"name": "_math_implementation",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_gauge_implementation",
"inputs": [
{
"name": "_gauge_implementation",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_views_implementation",
"inputs": [
{
"name": "_views_implementation",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "commit_transfer_ownership",
"inputs": [
{
"name": "_addr",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "accept_transfer_ownership",
"inputs": [],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_fee_receiver",
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_fee_receiver",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "add_asset_type",
"inputs": [
{
"name": "_id",
"type": "uint8"
},
{
"name": "_name",
"type": "string"
}
],
"outputs": []
},
{
"stateMutability": "view",
"type": "function",
"name": "admin",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "future_admin",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "asset_types",
"inputs": [
{
"name": "arg0",
"type": "uint8"
}
],
"outputs": [
{
"name": "",
"type": "string"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "pool_list",
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "pool_count",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "base_pool_list",
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "base_pool_count",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "base_pool_data",
"inputs": [
{
"name": "arg0",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "tuple",
"components": [
{
"name": "lp_token",
"type": "address"
},
{
"name": "coins",
"type": "address[]"
},
{
"name": "decimals",
"type": "uint256"
},
{
"name": "n_coins",
"type": "uint256"
},
{
"name": "asset_types",
"type": "uint8[]"
}
]
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "base_pool_assets",
"inputs": [
{
"name": "arg0",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "bool"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "pool_implementations",
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "metapool_implementations",
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "math_implementation",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "gauge_implementation",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "views_implementation",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "fee_receiver",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
}
]

View File

@@ -0,0 +1,751 @@
[
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "pool",
"type": "address"
}
],
"name": "PoolAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "basepool",
"type": "address"
}
],
"name": "BasePoolAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "pool",
"type": "address"
}
],
"name": "PoolRemoved",
"type": "event"
},
{
"inputs": [
{
"name": "_address_provider",
"type": "address"
},
{
"name": "_base_pool_registry",
"type": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"name": "find_pool_for_coins",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "i",
"type": "uint256"
}
],
"name": "find_pool_for_coins",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_n_coins",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_n_underlying_coins",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_coins",
"outputs": [
{
"name": "",
"type": "address[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_underlying_coins",
"outputs": [
{
"name": "",
"type": "address[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_decimals",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_underlying_decimals",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_gauges",
"outputs": [
{
"name": "",
"type": "address[10]"
},
{
"name": "",
"type": "int128[10]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_balances",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_underlying_balances",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "get_virtual_price_from_lp_token",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_A",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_D",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_gamma",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_fees",
"outputs": [
{
"name": "",
"type": "uint256[4]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_admin_balances",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"name": "get_coin_indices",
"outputs": [
{
"name": "",
"type": "int128"
},
{
"name": "",
"type": "int128"
},
{
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "is_meta",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_base_pool",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_pool_name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_lp_token",
"type": "address"
},
{
"name": "_gauge",
"type": "address"
},
{
"name": "_zap",
"type": "address"
},
{
"name": "_n_coins",
"type": "uint256"
},
{
"name": "_name",
"type": "string"
}
],
"name": "add_pool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_lp_token",
"type": "address"
},
{
"name": "_gauge",
"type": "address"
},
{
"name": "_zap",
"type": "address"
},
{
"name": "_n_coins",
"type": "uint256"
},
{
"name": "_name",
"type": "string"
},
{
"name": "_base_pool",
"type": "address"
}
],
"name": "add_pool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_lp_token",
"type": "address"
},
{
"name": "_gauge",
"type": "address"
},
{
"name": "_zap",
"type": "address"
},
{
"name": "_n_coins",
"type": "uint256"
},
{
"name": "_name",
"type": "string"
},
{
"name": "_base_pool",
"type": "address"
},
{
"name": "_has_positive_rebasing_tokens",
"type": "bool"
}
],
"name": "add_pool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "remove_pool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_liquidity_gauges",
"type": "address[10]"
}
],
"name": "set_liquidity_gauges",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_pools",
"type": "address[10]"
},
{
"name": "_liquidity_gauges",
"type": "address[10]"
}
],
"name": "batch_set_liquidity_gauges",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "address_provider",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "base_pool_registry",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"name": "pool_list",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pool_count",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "base_pool_count",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"name": "get_coin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "coin_count",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "arg0",
"type": "address"
}
],
"name": "get_pool_from_lp_token",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "arg0",
"type": "address"
}
],
"name": "get_lp_token",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "arg0",
"type": "address"
}
],
"name": "get_zap",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "last_updated",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]

View File

@@ -0,0 +1,222 @@
[
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "balance",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"payable": true,
"stateMutability": "payable",
"type": "fallback"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "owner",
"type": "address"
},
{
"indexed": true,
"name": "spender",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "from",
"type": "address"
},
{
"indexed": true,
"name": "to",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
}
]

View File

@@ -0,0 +1,49 @@
#!/usr/bin/python
import json
import os
import re
import time
import urllib.request
# Exports contract ABI in JSON
abis = {
# Factories
"CryptoSwapRegistry": "0x9a32aF1A11D9c937aEa61A3790C2983257eA8Bc0",
"MainRegistry": "0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5",
"MetaPoolFactory": "0xB9fC157394Af804a3578134A6585C0dc9cc990d4",
"CryptoPoolFactory": "0xF18056Bbd320E96A48e3Fbf8bC061322531aac99",
# pool
"Pool": "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7",
"3Pool": "0x5F890841f657d90E081bAbdB532A05996Af79Fe6",
}
ABI_ENDPOINT = (
"https://api.etherscan.io/api?module=contract&action=getabi&address={address}"
)
if etherscan_key := os.environ.get("ETHERSCAN_API_TOKEN"):
print("API KEY Loaded!")
ABI_ENDPOINT += f"&apikey={etherscan_key}"
def __main__():
for name, addr in abis.items():
normalized_name = "_".join(re.findall(r"[A-Z]+[a-z]*", name)).lower()
print(f"Getting ABI for {name} at {addr} ({normalized_name})")
try:
with urllib.request.urlopen(ABI_ENDPOINT.format(address=addr)) as response:
response_json = json.loads(response.read().decode())
abi_json = json.loads(response_json["result"])
result = json.dumps(abi_json, indent=4, sort_keys=True)
with open(f"{normalized_name}.json", "w") as f:
f.write(result)
except Exception as err:
print(response.content)
raise err
time.sleep(0.25)
if __name__ == "__main__":
__main__()

View File

@@ -0,0 +1,940 @@
[
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "pool",
"type": "address"
},
{
"indexed": false,
"name": "rate_method_id",
"type": "bytes"
}
],
"name": "PoolAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "pool",
"type": "address"
}
],
"name": "PoolRemoved",
"type": "event"
},
{
"inputs": [
{
"name": "_address_provider",
"type": "address"
},
{
"name": "_gauge_controller",
"type": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"name": "find_pool_for_coins",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "i",
"type": "uint256"
}
],
"name": "find_pool_for_coins",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 1521,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_n_coins",
"outputs": [
{
"name": "",
"type": "uint256[2]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 12102,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_coins",
"outputs": [
{
"name": "",
"type": "address[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 12194,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_underlying_coins",
"outputs": [
{
"name": "",
"type": "address[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 7874,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_decimals",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 7966,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_underlying_decimals",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 36992,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_rates",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 20157,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_gauges",
"outputs": [
{
"name": "",
"type": "address[10]"
},
{
"name": "",
"type": "int128[10]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 16583,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_balances",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 162842,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_underlying_balances",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 1927,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "get_virtual_price_from_lp_token",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 1045,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_A",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 6305,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_parameters",
"outputs": [
{
"name": "A",
"type": "uint256"
},
{
"name": "future_A",
"type": "uint256"
},
{
"name": "fee",
"type": "uint256"
},
{
"name": "admin_fee",
"type": "uint256"
},
{
"name": "future_fee",
"type": "uint256"
},
{
"name": "future_admin_fee",
"type": "uint256"
},
{
"name": "future_owner",
"type": "address"
},
{
"name": "initial_A",
"type": "uint256"
},
{
"name": "initial_A_time",
"type": "uint256"
},
{
"name": "future_A_time",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 1450,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_fees",
"outputs": [
{
"name": "",
"type": "uint256[2]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 36454,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_admin_balances",
"outputs": [
{
"name": "",
"type": "uint256[8]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 27131,
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"name": "get_coin_indices",
"outputs": [
{
"name": "",
"type": "int128"
},
{
"name": "",
"type": "int128"
},
{
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 32004,
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"name": "estimate_gas_used",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 1900,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "is_meta",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 8323,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_pool_name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 1951,
"inputs": [
{
"name": "_coin",
"type": "address"
}
],
"name": "get_coin_swap_count",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2090,
"inputs": [
{
"name": "_coin",
"type": "address"
},
{
"name": "_index",
"type": "uint256"
}
],
"name": "get_coin_swap_complement",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2011,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "get_pool_asset_type",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 61485845,
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_n_coins",
"type": "uint256"
},
{
"name": "_lp_token",
"type": "address"
},
{
"name": "_rate_info",
"type": "bytes32"
},
{
"name": "_decimals",
"type": "uint256"
},
{
"name": "_underlying_decimals",
"type": "uint256"
},
{
"name": "_has_initial_A",
"type": "bool"
},
{
"name": "_is_v1",
"type": "bool"
},
{
"name": "_name",
"type": "string"
}
],
"name": "add_pool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"gas": 31306062,
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_n_coins",
"type": "uint256"
},
{
"name": "_lp_token",
"type": "address"
},
{
"name": "_rate_info",
"type": "bytes32"
},
{
"name": "_decimals",
"type": "uint256"
},
{
"name": "_use_rates",
"type": "uint256"
},
{
"name": "_has_initial_A",
"type": "bool"
},
{
"name": "_is_v1",
"type": "bool"
},
{
"name": "_name",
"type": "string"
}
],
"name": "add_pool_without_underlying",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_n_coins",
"type": "uint256"
},
{
"name": "_lp_token",
"type": "address"
},
{
"name": "_decimals",
"type": "uint256"
},
{
"name": "_name",
"type": "string"
}
],
"name": "add_metapool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_n_coins",
"type": "uint256"
},
{
"name": "_lp_token",
"type": "address"
},
{
"name": "_decimals",
"type": "uint256"
},
{
"name": "_name",
"type": "string"
},
{
"name": "_base_pool",
"type": "address"
}
],
"name": "add_metapool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"gas": 779731418758,
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"name": "remove_pool",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"gas": 390460,
"inputs": [
{
"name": "_addr",
"type": "address[5]"
},
{
"name": "_amount",
"type": "uint256[2][5]"
}
],
"name": "set_pool_gas_estimates",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"gas": 392047,
"inputs": [
{
"name": "_addr",
"type": "address[10]"
},
{
"name": "_amount",
"type": "uint256[10]"
}
],
"name": "set_coin_gas_estimates",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"gas": 72629,
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_estimator",
"type": "address"
}
],
"name": "set_gas_estimate_contract",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"gas": 400675,
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_liquidity_gauges",
"type": "address[10]"
}
],
"name": "set_liquidity_gauges",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"gas": 72667,
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_asset_type",
"type": "uint256"
}
],
"name": "set_pool_asset_type",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"gas": 1173447,
"inputs": [
{
"name": "_pools",
"type": "address[32]"
},
{
"name": "_asset_types",
"type": "uint256[32]"
}
],
"name": "batch_set_pool_asset_type",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"gas": 2048,
"inputs": [],
"name": "address_provider",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2078,
"inputs": [],
"name": "gauge_controller",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2217,
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"name": "pool_list",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2138,
"inputs": [],
"name": "pool_count",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2168,
"inputs": [],
"name": "coin_count",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2307,
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"name": "get_coin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2443,
"inputs": [
{
"name": "arg0",
"type": "address"
}
],
"name": "get_pool_from_lp_token",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2473,
"inputs": [
{
"name": "arg0",
"type": "address"
}
],
"name": "get_lp_token",
"outputs": [
{
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"gas": 2288,
"inputs": [],
"name": "last_updated",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,760 @@
[
{
"name": "TokenExchange",
"inputs": [
{
"type": "address",
"name": "buyer",
"indexed": true
},
{
"type": "int128",
"name": "sold_id",
"indexed": false
},
{
"type": "uint256",
"name": "tokens_sold",
"indexed": false
},
{
"type": "int128",
"name": "bought_id",
"indexed": false
},
{
"type": "uint256",
"name": "tokens_bought",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "TokenExchangeUnderlying",
"inputs": [
{
"type": "address",
"name": "buyer",
"indexed": true
},
{
"type": "int128",
"name": "sold_id",
"indexed": false
},
{
"type": "uint256",
"name": "tokens_sold",
"indexed": false
},
{
"type": "int128",
"name": "bought_id",
"indexed": false
},
{
"type": "uint256",
"name": "tokens_bought",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "AddLiquidity",
"inputs": [
{
"type": "address",
"name": "provider",
"indexed": true
},
{
"type": "uint256[4]",
"name": "token_amounts",
"indexed": false
},
{
"type": "uint256[4]",
"name": "fees",
"indexed": false
},
{
"type": "uint256",
"name": "invariant",
"indexed": false
},
{
"type": "uint256",
"name": "token_supply",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "RemoveLiquidity",
"inputs": [
{
"type": "address",
"name": "provider",
"indexed": true
},
{
"type": "uint256[4]",
"name": "token_amounts",
"indexed": false
},
{
"type": "uint256[4]",
"name": "fees",
"indexed": false
},
{
"type": "uint256",
"name": "token_supply",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "RemoveLiquidityImbalance",
"inputs": [
{
"type": "address",
"name": "provider",
"indexed": true
},
{
"type": "uint256[4]",
"name": "token_amounts",
"indexed": false
},
{
"type": "uint256[4]",
"name": "fees",
"indexed": false
},
{
"type": "uint256",
"name": "invariant",
"indexed": false
},
{
"type": "uint256",
"name": "token_supply",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "CommitNewAdmin",
"inputs": [
{
"type": "uint256",
"name": "deadline",
"indexed": true,
"unit": "sec"
},
{
"type": "address",
"name": "admin",
"indexed": true
}
],
"anonymous": false,
"type": "event"
},
{
"name": "NewAdmin",
"inputs": [
{
"type": "address",
"name": "admin",
"indexed": true
}
],
"anonymous": false,
"type": "event"
},
{
"name": "CommitNewParameters",
"inputs": [
{
"type": "uint256",
"name": "deadline",
"indexed": true,
"unit": "sec"
},
{
"type": "uint256",
"name": "A",
"indexed": false
},
{
"type": "uint256",
"name": "fee",
"indexed": false
},
{
"type": "uint256",
"name": "admin_fee",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "NewParameters",
"inputs": [
{
"type": "uint256",
"name": "A",
"indexed": false
},
{
"type": "uint256",
"name": "fee",
"indexed": false
},
{
"type": "uint256",
"name": "admin_fee",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"outputs": [],
"inputs": [
{
"type": "address[4]",
"name": "_coins"
},
{
"type": "address[4]",
"name": "_underlying_coins"
},
{
"type": "address",
"name": "_pool_token"
},
{
"type": "uint256",
"name": "_A"
},
{
"type": "uint256",
"name": "_fee"
}
],
"constant": false,
"payable": false,
"type": "constructor"
},
{
"name": "get_virtual_price",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 1570535
},
{
"name": "calc_token_amount",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [
{
"type": "uint256[4]",
"name": "amounts"
},
{
"type": "bool",
"name": "deposit"
}
],
"constant": true,
"payable": false,
"type": "function",
"gas": 6103471
},
{
"name": "add_liquidity",
"outputs": [],
"inputs": [
{
"type": "uint256[4]",
"name": "amounts"
},
{
"type": "uint256",
"name": "min_mint_amount"
}
],
"constant": false,
"payable": false,
"type": "function",
"gas": 9331701
},
{
"name": "get_dy",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [
{
"type": "int128",
"name": "i"
},
{
"type": "int128",
"name": "j"
},
{
"type": "uint256",
"name": "dx"
}
],
"constant": true,
"payable": false,
"type": "function",
"gas": 3489637
},
{
"name": "get_dy_underlying",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [
{
"type": "int128",
"name": "i"
},
{
"type": "int128",
"name": "j"
},
{
"type": "uint256",
"name": "dx"
}
],
"constant": true,
"payable": false,
"type": "function",
"gas": 3489467
},
{
"name": "exchange",
"outputs": [],
"inputs": [
{
"type": "int128",
"name": "i"
},
{
"type": "int128",
"name": "j"
},
{
"type": "uint256",
"name": "dx"
},
{
"type": "uint256",
"name": "min_dy"
}
],
"constant": false,
"payable": false,
"type": "function",
"gas": 7034253
},
{
"name": "exchange_underlying",
"outputs": [],
"inputs": [
{
"type": "int128",
"name": "i"
},
{
"type": "int128",
"name": "j"
},
{
"type": "uint256",
"name": "dx"
},
{
"type": "uint256",
"name": "min_dy"
}
],
"constant": false,
"payable": false,
"type": "function",
"gas": 7050488
},
{
"name": "remove_liquidity",
"outputs": [],
"inputs": [
{
"type": "uint256",
"name": "_amount"
},
{
"type": "uint256[4]",
"name": "min_amounts"
}
],
"constant": false,
"payable": false,
"type": "function",
"gas": 241191
},
{
"name": "remove_liquidity_imbalance",
"outputs": [],
"inputs": [
{
"type": "uint256[4]",
"name": "amounts"
},
{
"type": "uint256",
"name": "max_burn_amount"
}
],
"constant": false,
"payable": false,
"type": "function",
"gas": 9330864
},
{
"name": "commit_new_parameters",
"outputs": [],
"inputs": [
{
"type": "uint256",
"name": "amplification"
},
{
"type": "uint256",
"name": "new_fee"
},
{
"type": "uint256",
"name": "new_admin_fee"
}
],
"constant": false,
"payable": false,
"type": "function",
"gas": 146045
},
{
"name": "apply_new_parameters",
"outputs": [],
"inputs": [],
"constant": false,
"payable": false,
"type": "function",
"gas": 133452
},
{
"name": "revert_new_parameters",
"outputs": [],
"inputs": [],
"constant": false,
"payable": false,
"type": "function",
"gas": 21775
},
{
"name": "commit_transfer_ownership",
"outputs": [],
"inputs": [
{
"type": "address",
"name": "_owner"
}
],
"constant": false,
"payable": false,
"type": "function",
"gas": 74452
},
{
"name": "apply_transfer_ownership",
"outputs": [],
"inputs": [],
"constant": false,
"payable": false,
"type": "function",
"gas": 60508
},
{
"name": "revert_transfer_ownership",
"outputs": [],
"inputs": [],
"constant": false,
"payable": false,
"type": "function",
"gas": 21865
},
{
"name": "withdraw_admin_fees",
"outputs": [],
"inputs": [],
"constant": false,
"payable": false,
"type": "function",
"gas": 23448
},
{
"name": "kill_me",
"outputs": [],
"inputs": [],
"constant": false,
"payable": false,
"type": "function",
"gas": 37818
},
{
"name": "unkill_me",
"outputs": [],
"inputs": [],
"constant": false,
"payable": false,
"type": "function",
"gas": 21955
},
{
"name": "coins",
"outputs": [
{
"type": "address",
"name": ""
}
],
"inputs": [
{
"type": "int128",
"name": "arg0"
}
],
"constant": true,
"payable": false,
"type": "function",
"gas": 2130
},
{
"name": "underlying_coins",
"outputs": [
{
"type": "address",
"name": ""
}
],
"inputs": [
{
"type": "int128",
"name": "arg0"
}
],
"constant": true,
"payable": false,
"type": "function",
"gas": 2160
},
{
"name": "balances",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [
{
"type": "int128",
"name": "arg0"
}
],
"constant": true,
"payable": false,
"type": "function",
"gas": 2190
},
{
"name": "A",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2021
},
{
"name": "fee",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2051
},
{
"name": "admin_fee",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2081
},
{
"name": "owner",
"outputs": [
{
"type": "address",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2111
},
{
"name": "admin_actions_deadline",
"outputs": [
{
"type": "uint256",
"unit": "sec",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2141
},
{
"name": "transfer_ownership_deadline",
"outputs": [
{
"type": "uint256",
"unit": "sec",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2171
},
{
"name": "future_A",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2201
},
{
"name": "future_fee",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2231
},
{
"name": "future_admin_fee",
"outputs": [
{
"type": "uint256",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2261
},
{
"name": "future_owner",
"outputs": [
{
"type": "address",
"name": ""
}
],
"inputs": [],
"constant": true,
"payable": false,
"type": "function",
"gas": 2291
}
]

View File

@@ -0,0 +1,664 @@
[
{
"name": "TricryptoPoolDeployed",
"inputs": [
{
"name": "pool",
"type": "address",
"indexed": false
},
{
"name": "name",
"type": "string",
"indexed": false
},
{
"name": "symbol",
"type": "string",
"indexed": false
},
{
"name": "weth",
"type": "address",
"indexed": false
},
{
"name": "coins",
"type": "address[3]",
"indexed": false
},
{
"name": "math",
"type": "address",
"indexed": false
},
{
"name": "salt",
"type": "bytes32",
"indexed": false
},
{
"name": "packed_precisions",
"type": "uint256",
"indexed": false
},
{
"name": "packed_A_gamma",
"type": "uint256",
"indexed": false
},
{
"name": "packed_fee_params",
"type": "uint256",
"indexed": false
},
{
"name": "packed_rebalancing_params",
"type": "uint256",
"indexed": false
},
{
"name": "packed_prices",
"type": "uint256",
"indexed": false
},
{
"name": "deployer",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "LiquidityGaugeDeployed",
"inputs": [
{
"name": "pool",
"type": "address",
"indexed": false
},
{
"name": "gauge",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "UpdateFeeReceiver",
"inputs": [
{
"name": "_old_fee_receiver",
"type": "address",
"indexed": false
},
{
"name": "_new_fee_receiver",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "UpdatePoolImplementation",
"inputs": [
{
"name": "_implemention_id",
"type": "uint256",
"indexed": false
},
{
"name": "_old_pool_implementation",
"type": "address",
"indexed": false
},
{
"name": "_new_pool_implementation",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "UpdateGaugeImplementation",
"inputs": [
{
"name": "_old_gauge_implementation",
"type": "address",
"indexed": false
},
{
"name": "_new_gauge_implementation",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "UpdateMathImplementation",
"inputs": [
{
"name": "_old_math_implementation",
"type": "address",
"indexed": false
},
{
"name": "_new_math_implementation",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "UpdateViewsImplementation",
"inputs": [
{
"name": "_old_views_implementation",
"type": "address",
"indexed": false
},
{
"name": "_new_views_implementation",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"name": "TransferOwnership",
"inputs": [
{
"name": "_old_owner",
"type": "address",
"indexed": false
},
{
"name": "_new_owner",
"type": "address",
"indexed": false
}
],
"anonymous": false,
"type": "event"
},
{
"stateMutability": "nonpayable",
"type": "constructor",
"inputs": [
{
"name": "_fee_receiver",
"type": "address"
},
{
"name": "_admin",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "deploy_pool",
"inputs": [
{
"name": "_name",
"type": "string"
},
{
"name": "_symbol",
"type": "string"
},
{
"name": "_coins",
"type": "address[3]"
},
{
"name": "_weth",
"type": "address"
},
{
"name": "implementation_id",
"type": "uint256"
},
{
"name": "A",
"type": "uint256"
},
{
"name": "gamma",
"type": "uint256"
},
{
"name": "mid_fee",
"type": "uint256"
},
{
"name": "out_fee",
"type": "uint256"
},
{
"name": "fee_gamma",
"type": "uint256"
},
{
"name": "allowed_extra_profit",
"type": "uint256"
},
{
"name": "adjustment_step",
"type": "uint256"
},
{
"name": "ma_exp_time",
"type": "uint256"
},
{
"name": "initial_prices",
"type": "uint256[2]"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "deploy_gauge",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_fee_receiver",
"inputs": [
{
"name": "_fee_receiver",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_pool_implementation",
"inputs": [
{
"name": "_pool_implementation",
"type": "address"
},
{
"name": "_implementation_index",
"type": "uint256"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_gauge_implementation",
"inputs": [
{
"name": "_gauge_implementation",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_views_implementation",
"inputs": [
{
"name": "_views_implementation",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "set_math_implementation",
"inputs": [
{
"name": "_math_implementation",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "commit_transfer_ownership",
"inputs": [
{
"name": "_addr",
"type": "address"
}
],
"outputs": []
},
{
"stateMutability": "nonpayable",
"type": "function",
"name": "accept_transfer_ownership",
"inputs": [],
"outputs": []
},
{
"stateMutability": "view",
"type": "function",
"name": "find_pool_for_coins",
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "find_pool_for_coins",
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "i",
"type": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_coins",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address[3]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_decimals",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256[3]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_balances",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256[3]"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_coin_indices",
"inputs": [
{
"name": "_pool",
"type": "address"
},
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256"
},
{
"name": "",
"type": "uint256"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_gauge",
"inputs": [
{
"name": "_pool",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "get_market_counts",
"inputs": [
{
"name": "coin_a",
"type": "address"
},
{
"name": "coin_b",
"type": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "admin",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "future_admin",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "fee_receiver",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "pool_implementations",
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "gauge_implementation",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "views_implementation",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "math_implementation",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "pool_count",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256"
}
]
},
{
"stateMutability": "view",
"type": "function",
"name": "pool_list",
"inputs": [
{
"name": "arg0",
"type": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address"
}
]
}
]

View File

@@ -0,0 +1,12 @@
version: v1
plugins:
- plugin: buf.build/community/neoeinstein-prost:v0.2.2
out: src/pb
opt:
- file_descriptor_set=false
- plugin: buf.build/community/neoeinstein-prost-crate:v0.3.1
out: src/pb
opt:
- no_features

View File

@@ -0,0 +1,44 @@
use anyhow::Result;
use std::{fs, io::Write};
use substreams_ethereum::Abigen;
fn main() -> Result<()> {
let abi_folder = "abi";
let output_folder = "src/abi";
let files = fs::read_dir(abi_folder)?;
let mut mod_rs_content = String::new();
mod_rs_content.push_str("#![allow(clippy::all)]\n");
for file in files {
let file = file?;
let file_name = file.file_name();
let file_name = file_name.to_string_lossy();
if !file_name.ends_with(".json") {
continue;
}
let contract_name = file_name.split('.').next().unwrap();
let input_path = format!("{}/{}", abi_folder, file_name);
let output_path = format!("{}/{}.rs", output_folder, contract_name);
mod_rs_content.push_str(&format!("pub mod {};\n", contract_name));
if std::path::Path::new(&output_path).exists() {
continue;
}
Abigen::new(contract_name, &input_path)?
.generate()?
.write_to_file(&output_path)?;
}
let mod_rs_path = format!("{}/mod.rs", output_folder);
let mut mod_rs_file = fs::File::create(mod_rs_path)?;
mod_rs_file.write_all(mod_rs_content.as_bytes())?;
Ok(())
}

View File

@@ -0,0 +1,51 @@
[
{
"name": "3pool",
"address": "bebc44782c7db0a1a60cb6fe97d0b483032ff1c7",
"tx_hash": "20793bbf260912aae189d5d261ff003c9b9166da8191d8f9d63ff1c7722f3ac6",
"tokens": [
"6b175474e89094c44da98b954eedeac495271d0f",
"a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"dac17f958d2ee523a2206206994597c13d831ec7"
]
},
{
"name": "steth",
"address": "dc24316b9ae028f1497c275eb9192a3ea0f67022",
"tx_hash": "fac67ecbd423a5b915deff06045ec9343568edaec34ae95c43d35f2c018afdaa",
"tokens": [
"EeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
"ae7ab96520DE3A18E5e111B5EaAb095312D7fE84"
]
},
{
"name": "tricrypto2",
"address": "d51a44d3fae010294c616388b506acda1bfaae46",
"tx_hash": "dafb6385ed988ce8aacecfe1d97b38ea5e60b1ebce74d2423f71ddd621680138",
"tokens": [
"dAC17F958D2ee523a2206206994597C13D831ec7",
"2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599",
"C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
]
},
{
"name": "susd",
"address": "A5407eAE9Ba41422680e2e00537571bcC53efBfD",
"tx_hash": "51aca4a03a395de8855fa2ca59b7febe520c2a223e69c502066162f7c1a95ec2",
"tokens": [
"6B175474E89094C44Da98b954EedeAC495271d0F",
"A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"dAC17F958D2ee523a2206206994597C13D831ec7",
"57Ab1ec28D129707052df4dF418D58a2D46d5f51"
]
},
{
"name": "fraxusdc",
"address": "DcEF968d416a41Cdac0ED8702fAC8128A64241A2",
"tx_hash": "1f4254004ce9e19d4eb742ee5a69d30f29085902d976f73e97c44150225ef775",
"tokens": [
"853d955aCEf822Db058eb8505911ED77F175b99e",
"A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
]
}
]

View File

@@ -0,0 +1,51 @@
import json
from typing import Any
PARAMETERS = "params.json"
EMPTY = "0x0000000000000000000000000000000000000000"
INITIAL_BLOCK = 17258001
def encode_json_to_query_params(params: list[dict[str, Any]]):
encoded_params = []
try:
for i, param in enumerate(params):
address: str = param["address"]
tx_hash: str = param["tx_hash"]
tokens: list[str] = param["tokens"]
attributes: dict[str, str] = param.get("attributes", {})
attributes["name"] = param["name"]
attributes["factory_name"] = "NA"
attributes["factory"] = EMPTY
encoded_address = f"address={address}"
encoded_tx_hash = f"tx_hash={tx_hash}"
encoded_tokens = "&".join([f"tokens[]={token}" for token in tokens])
encoded_attributes = "&".join(
[
f"attribute_keys[]={key}&attribute_vals[]={value}"
for key, value in attributes.items()
]
)
encoded_param = f"{encoded_address}&{encoded_tx_hash}&{encoded_tokens}&{encoded_attributes}"
encoded_param = encoded_param.rstrip("&")
encoded_params.append(encoded_param)
except KeyError as err:
raise KeyError(
f"Missing key in {PARAMETERS}.\n"
f"Index `{i}` object missing parameters.\n\n" + err.args[0]
)
return ",".join(encoded_params)
def main():
with open(PARAMETERS, "r") as f:
params = json.load(f)
print(encode_json_to_query_params(params))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,19 @@
syntax = "proto3";
package eth.factory.v1;
message Pools {
repeated Pool pools = 1;
}
message Pool {
bytes pool_id = 1;
fixed64 log_ordinal = 2;
}
message Transfer {
bytes from = 1;
bytes to = 2;
string token = 3;
string amount = 4;
}

View File

@@ -0,0 +1,15 @@
syntax = "proto3";
package eth.pool.v1;
message Transfers {
repeated Transfer transfers = 1;
}
message Transfer {
string from = 1;
string to = 2;
uint64 token_id = 3;
string trx_hash = 4;
uint64 ordinal = 5;
}

View File

@@ -0,0 +1 @@
substreams gui -e mainnet.eth.streamingfast.io:443 substreams.yaml map_protocol_changes --start-block 9906598 --stop-block +50 -p map_components=`python params.py`

View File

@@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
#![allow(clippy::all)]
pub mod crypto_pool_factory;
pub mod stableswap_factory;
pub mod susd;
pub mod crypto_swap_ng_factory;
pub mod meta_registry;
pub mod tricrypto_factory;
pub mod main_registry;
pub mod erc20;
pub mod meta_pool_factory;
pub mod crypto_swap_registry;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
use substreams::hex;
// Registries
pub const META_REGISTRY: [u8; 20] = hex!("F98B45FA17DE75FB1aD0e7aFD971b0ca00e379fC");
// Factories
pub const CRYPTO_POOL_FACTORY: [u8; 20] = hex!("F18056Bbd320E96A48e3Fbf8bC061322531aac99");
pub const META_POOL_FACTORY: [u8; 20] = hex!("B9fC157394Af804a3578134A6585C0dc9cc990d4");
pub const META_POOL_FACTORY_OLD: [u8; 20] = hex!("0959158b6040D32d04c301A72CBFD6b39E21c9AE");
pub const CRYPTO_SWAP_NG_FACTORY: [u8; 20] = hex!("6A8cbed756804B16E05E741eDaBd5cB544AE21bf");
pub const TRICRYPTO_FACTORY: [u8; 20] = hex!("0c0e5f2fF0ff18a3be9b835635039256dC4B4963");
pub const STABLESWAP_FACTORY: [u8; 20] = hex!("4F8846Ae9380B90d2E71D5e3D042dff3E7ebb40d");
// Important addresses
pub const WETH_ADDRESS: [u8; 20] = hex!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
pub const ETH_ADDRESS: [u8; 20] = hex!("EeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE");

View File

@@ -0,0 +1,7 @@
#![allow(clippy::not_unsafe_ptr_arg_deref)]
mod abi;
mod consts;
pub mod modules;
mod pool_changes;
mod pool_factories;
mod pools;

View File

@@ -0,0 +1,290 @@
use std::collections::HashMap;
use anyhow::Result;
use itertools::Itertools;
use substreams::{
pb::substreams::StoreDeltas,
scalar::BigInt,
store::{StoreAddBigInt, StoreGet, StoreGetString, StoreNew, StoreSet, StoreSetString},
};
use substreams_ethereum::pb::eth;
use crate::{
pool_changes::{emit_deltas, emit_eth_deltas},
pool_factories,
pools::emit_specific_pools,
};
use tycho_substreams::{
balances::store_balance_changes, contract::extract_contract_changes, prelude::*,
};
/// This struct purely exists to spoof the `PartialEq` trait for `Transaction` so we can use it in
/// a later groupby operation.
#[derive(Debug)]
struct TransactionWrapper(Transaction);
impl PartialEq for TransactionWrapper {
fn eq(&self, other: &Self) -> bool {
self.0.hash == other.0.hash
}
}
#[substreams::handlers::map]
pub fn map_components(
params: String,
block: eth::v2::Block,
) -> Result<BlockTransactionProtocolComponents> {
// Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call
// We store these as a hashmap by tx hash since we need to agg by tx hash later
Ok(BlockTransactionProtocolComponents {
tx_components: block
.transactions()
.filter_map(|tx| {
let mut components = tx
.logs_with_calls()
.filter(|(_, call)| !call.call.state_reverted)
.filter_map(|(log, call)| {
pool_factories::address_map(
call.call
.address
.as_slice()
.try_into()
.ok()?, // this shouldn't fail
log,
call.call,
tx,
)
})
.collect::<Vec<_>>();
if let Some(component) = emit_specific_pools(&params, tx).expect(
"An unexpected error occured when parsing params for emitting specific pools",
) {
components.push(component)
}
if !components.is_empty() {
Some(TransactionProtocolComponents {
tx: Some(Transaction {
hash: tx.hash.clone(),
from: tx.from.clone(),
to: tx.to.clone(),
index: Into::<u64>::into(tx.index),
}),
components,
})
} else {
None
}
})
.collect::<Vec<_>>(),
})
}
/// Simply stores the `ProtocolComponent`s with the pool id as the key and tokens as the value
#[substreams::handlers::store]
pub fn store_component_tokens(map: BlockTransactionProtocolComponents, store: StoreSetString) {
map.tx_components
.iter()
.flat_map(|tx_components| &tx_components.components)
.for_each(|component| {
store.set(
0,
format!("pool:{0}", component.id),
&component
.tokens
.iter()
.map(hex::encode)
.join(":"),
);
});
}
/// Since the `PoolBalanceChanged` events administer only deltas, we need to leverage a map and a
/// store to be able to tally up final balances for tokens in a pool.
#[substreams::handlers::map]
pub fn map_relative_balances(
block: eth::v2::Block,
tokens_store: StoreGetString,
) -> Result<BlockBalanceDeltas, anyhow::Error> {
Ok(BlockBalanceDeltas {
balance_deltas: {
let mut deltas: Vec<_> = block
.transactions()
.flat_map(|tx| {
emit_eth_deltas(tx, &tokens_store)
.into_iter()
.chain(emit_deltas(tx, &tokens_store))
})
.collect();
// Keep it consistent with how it's inserted in the store. This step is important
// because we use a zip on the store deltas and balance deltas later.
deltas.sort_unstable_by(|a, b| a.ord.cmp(&b.ord));
deltas
},
})
}
/// It's significant to include both the `pool_id` and the `token_id` for each balance delta as the
/// store key to ensure that there's a unique balance being tallied for each.
#[substreams::handlers::store]
pub fn store_balances(deltas: BlockBalanceDeltas, store: StoreAddBigInt) {
store_balance_changes(deltas, store)
}
/// This is the main map that handles most of the indexing of this substream.
/// Every contract change is grouped by transaction index via the `transaction_contract_changes`
/// map. Each block of code will extend the `TransactionContractChanges` struct with the
/// cooresponding changes (balance, component, contract), inserting a new one if it doesn't exist.
/// At the very end, the map can easily be sorted by index to ensure the final
/// `BlockContractChanges` is ordered by transactions properly.
#[substreams::handlers::map]
pub fn map_protocol_changes(
block: eth::v2::Block,
grouped_components: BlockTransactionProtocolComponents,
deltas: BlockBalanceDeltas,
components_store: StoreGetString,
balance_store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store.
) -> Result<BlockContractChanges> {
// We merge contract changes by transaction (identified by transaction index) making it easy to
// sort them at the very end.
let mut transaction_contract_changes: HashMap<_, TransactionContractChanges> = HashMap::new();
// `ProtocolComponents` are gathered from `map_pools_created` which just need a bit of work to
// convert into `TransactionContractChanges`
grouped_components
.tx_components
.into_iter()
.for_each(|tx_component| {
let tx = tx_component.tx.as_ref().unwrap();
transaction_contract_changes
.entry(tx.index)
.or_insert_with(|| TransactionContractChanges {
tx: Some(tx.clone()),
contract_changes: vec![],
component_changes: vec![],
balance_changes: vec![],
})
.component_changes
.extend_from_slice(
&(tx_component
.components
.into_iter()
.map(|mut component| {
component.id = format!("0x{}", component.id);
component
})
.collect::<Vec<_>>()),
);
});
// Balance changes are gathered by the `StoreDelta` based on `TokenExchange`, etc. creating
// `BalanceDeltas`. We essentially just process the changes that occured to the `store` this
// block. Then, these balance changes are merged onto the existing map of tx contract changes,
// inserting a new one if it doesn't exist.
balance_store
.deltas
.into_iter()
.zip(deltas.balance_deltas)
.map(|(store_delta, balance_delta)| {
let new_value_string = String::from_utf8(store_delta.new_value)
.unwrap()
.to_string();
(
balance_delta.tx.unwrap(),
BalanceChange {
token: balance_delta.token,
balance: BigInt::try_from(new_value_string)
.unwrap()
.to_signed_bytes_be(),
component_id: format!(
"0x{}",
String::from_utf8(balance_delta.component_id).unwrap()
)
.into(),
},
)
})
// We need to group the balance changes by tx hash for the `TransactionContractChanges` agg
.chunk_by(|(tx, _)| TransactionWrapper(tx.clone()))
.into_iter()
.for_each(|(tx_wrapped, group)| {
let tx = tx_wrapped.0;
transaction_contract_changes
.entry(tx.index)
.or_insert_with(|| TransactionContractChanges {
tx: Some(tx.clone()),
contract_changes: vec![],
component_changes: vec![],
balance_changes: vec![],
})
.balance_changes
.extend(group.map(|(_, change)| change));
});
// General helper for extracting contract changes. Uses block, our component store which holds
// all of our tracked deployed pool addresses, and the map of tx contract changes which we
// output into for final processing later.
extract_contract_changes(
&block,
|addr| {
components_store
.get_last(format!("pool:{0}", hex::encode(addr)))
.is_some()
},
&mut transaction_contract_changes,
);
for change in transaction_contract_changes.values_mut() {
for balance_change in change.balance_changes.iter_mut() {
replace_eth_address(&mut balance_change.token);
}
for component_change in change.component_changes.iter_mut() {
for token in component_change.tokens.iter_mut() {
replace_eth_address(token);
}
}
}
// Process all `transaction_contract_changes` for final output in the `BlockContractChanges`,
// sorted by transaction index (the key).
Ok(BlockContractChanges {
block: Some(Block {
number: block.number,
hash: block.hash.clone(),
parent_hash: block
.header
.as_ref()
.expect("Block header not present")
.parent_hash
.clone(),
ts: block.timestamp_seconds(),
}),
changes: transaction_contract_changes
.drain()
.sorted_unstable_by_key(|(index, _)| *index)
.filter_map(|(_, change)| {
if change.contract_changes.is_empty() &&
change.component_changes.is_empty() &&
change.balance_changes.is_empty()
{
None
} else {
Some(change)
}
})
.collect::<Vec<_>>(),
})
}
fn replace_eth_address(token: &mut Vec<u8>) {
let eth_address = [238u8; 20]; // 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
if *token == eth_address {
*token = [0u8; 20].to_vec();
}
}

View File

@@ -0,0 +1,121 @@
use substreams::{
scalar::BigInt,
store::{StoreGet, StoreGetString},
};
use substreams_ethereum::{pb::eth::v2::TransactionTrace, Event};
use tycho_substreams::prelude::*;
use crate::{
abi,
consts::{ETH_ADDRESS, WETH_ADDRESS},
};
fn get_pool_tokens(pool_address: &Vec<u8>, tokens_store: &StoreGetString) -> Option<Vec<String>> {
let pool_key = format!("pool:{}", hex::encode(pool_address));
Some(
tokens_store
.get_last(pool_key)?
.split(":")
.map(|token| token.to_owned())
.collect::<Vec<_>>(),
)
}
/// Tracks `Transfers` in and out of tracked pools if it matches the specific tokens.
pub fn emit_deltas(tx: &TransactionTrace, tokens_store: &StoreGetString) -> Vec<BalanceDelta> {
tx.logs_with_calls()
.filter_map(|(log, _)| {
let transfer = abi::erc20::events::Transfer::match_and_decode(log)?;
let (component_id, pool_tokens, is_incoming) =
if let Some(pool_tokens) = get_pool_tokens(&transfer.to, tokens_store) {
(hex::encode(&transfer.to), pool_tokens, true)
} else if let Some(pool_tokens) = get_pool_tokens(&transfer.from, tokens_store) {
(hex::encode(&transfer.from), pool_tokens, false)
} else {
return None;
};
let token_id = hex::encode(log.address.clone());
if pool_tokens.contains(&token_id) {
let delta = if is_incoming { transfer.value } else { transfer.value * -1 };
Some(BalanceDelta {
ord: log.ordinal,
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
token: hex::decode(token_id).unwrap(),
delta: delta.to_signed_bytes_be(),
component_id: component_id.into(),
})
} else {
None
}
})
.collect::<Vec<_>>()
}
/// Tracks ETH balance changes in and out of tracked pools if it matches the specific tokens.
/// Note: Pools might report as WETH or ETH. Some pools might even accept either WETH or ETH and
/// convert them on the fly (checkout pools with `WETHOptimized` in the name). It's a bit tricky
/// to figure this stuff out on the fly, but our rule of thumb is as follows:
/// - If a pool reports ETH in the `pool_tokens`, we use the fake ETH erc20 address.
/// - If a pool reports WETH, we report with the WETH erc20 address.
/// - If neither, it's likely an erroneous ETH transactions that many older pools don't reject.
pub fn emit_eth_deltas(tx: &TransactionTrace, tokens_store: &StoreGetString) -> Vec<BalanceDelta> {
tx.calls()
.flat_map(|call| {
call.call
.balance_changes
.iter()
.filter_map(|balance_change| {
if let Some(pool_tokens) =
get_pool_tokens(&balance_change.address, tokens_store)
{
let token = if pool_tokens.contains(&hex::encode(ETH_ADDRESS)) {
ETH_ADDRESS.to_vec()
} else if pool_tokens.contains(&hex::encode(WETH_ADDRESS)) {
WETH_ADDRESS.to_vec()
} else {
// The pool that was matched to the call doesn't contain either ETH
// or WETH so found eth balance changes are erroneous.
return None;
};
// We need to convert to the usable `BigInt` type to be able to calculate
// subtraction. This is seemingly the easiest way to do this.
let delta = BigInt::from_unsigned_bytes_be(
&balance_change
.new_value
.clone()
.unwrap_or_default()
.bytes,
) - BigInt::from_unsigned_bytes_be(
&balance_change
.old_value
.clone()
.unwrap_or_default()
.bytes,
);
Some(BalanceDelta {
ord: call.call.end_ordinal,
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
token,
delta: delta.to_signed_bytes_be(),
component_id: hex::encode(balance_change.address.clone()).into(),
})
} else {
None
}
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>()
}

View File

@@ -0,0 +1,715 @@
use substreams_ethereum::{
pb::eth::v2::{Call, Log, TransactionTrace},
Event, Function,
};
use crate::abi;
use tycho_substreams::prelude::*;
use substreams::scalar::BigInt;
use crate::consts::*;
/// This trait defines some helpers for serializing and deserializing `Vec<BigInt>` which is needed
/// to be able to encode some of the `Attribute`s. This should also be handled by any downstream
/// application.
#[allow(dead_code)]
trait SerializableVecBigInt {
fn serialize_bytes(&self) -> Vec<u8>;
fn deserialize_bytes(bytes: &[u8]) -> Vec<BigInt>;
}
impl SerializableVecBigInt for Vec<BigInt> {
fn serialize_bytes(&self) -> Vec<u8> {
self.iter()
.flat_map(|big_int| big_int.to_signed_bytes_be())
.collect()
}
fn deserialize_bytes(bytes: &[u8]) -> Vec<BigInt> {
bytes
.chunks_exact(32)
.map(BigInt::from_signed_bytes_be)
.collect::<Vec<BigInt>>()
}
}
/// Converts address bytes into a string containing a leading `0x`.
fn address_to_bytes_with_0x(address: &[u8; 20]) -> Vec<u8> {
format!("0x{}", hex::encode(address)).into_bytes()
}
/// Function that swaps `WETH` addresses for `ETH` address for specific factory types that decide
/// to use `WETH` address even though native `ETH` is stored. This is also extra weird bc ETH
/// doesn't even have a real address, so we use the standard `0xEEEee...`.
fn swap_weth_for_eth(tokens: Vec<Vec<u8>>) -> Vec<Vec<u8>> {
if tokens.contains(&WETH_ADDRESS.into()) {
tokens
.into_iter()
.map(|token| if token == WETH_ADDRESS { ETH_ADDRESS.into() } else { token })
.collect::<Vec<_>>()
} else {
tokens
}
}
/// This massive function matches factory address to specific logic to construct
/// `ProtocolComponent`s. While, most of the logic is readily replicable, several factories differ
/// in information density resulting in needing other information sources such as decoding calls
/// or even making RPC calls to provide extra details.
///
/// Each `ProtocolComponent` contains the following static attributes:
/// - `pool_type`: The type of pool, such as `crypto_pool`, `plain_pool`, `metapool`, etc.
/// - `name`: The name of the pool.
/// - `factory_name`: The name of the factory that created the pool.
/// - `factory`: The address of the factory that created the pool.
///
/// The basic flow of this function is as follows:
/// - Match the factory address
/// - Decode the relevant event from the log
/// - Attempt to decode the cooresponding function call (based on the permutation of the ABI)
/// - Optionally make an RPC call to produce further information (see metapools)
/// - Construct the cooresponding `ProtocolComponent`
pub fn address_map(
call_address: &[u8; 20],
log: &Log,
call: &Call,
tx: &TransactionTrace,
) -> Option<ProtocolComponent> {
match *call_address {
CRYPTO_POOL_FACTORY => {
let pool_added =
abi::crypto_pool_factory::events::CryptoPoolDeployed::match_and_decode(log)?;
let tokens = swap_weth_for_eth(pool_added.coins.into());
let component_id = &call.return_data[12..];
Some(ProtocolComponent {
id: hex::encode(component_id),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens,
contracts: vec![component_id.into()],
static_att: vec![
Attribute {
name: "pool_type".into(),
value: "crypto_pool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "name".into(),
value: pool_added.a.to_string().into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory_name".into(),
value: "crypto_pool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory".into(),
value: address_to_bytes_with_0x(&CRYPTO_POOL_FACTORY),
change: ChangeType::Creation.into(),
},
],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
})
}
META_POOL_FACTORY => {
if let Some(pool_added) =
abi::meta_pool_factory::events::PlainPoolDeployed::match_and_decode(log)
{
let add_pool =
abi::meta_pool_factory::functions::DeployPlainPool1::match_and_decode(call)
.map(|add_pool| abi::meta_pool_factory::functions::DeployPlainPool3 {
name: add_pool.name,
symbol: add_pool.symbol,
coins: add_pool.coins,
a: add_pool.a,
fee: add_pool.fee,
asset_type: BigInt::from(0),
implementation_idx: BigInt::from(0),
})
.or_else(|| {
abi::meta_pool_factory::functions::DeployPlainPool2::match_and_decode(
call,
)
.map(|add_pool| {
abi::meta_pool_factory::functions::DeployPlainPool3 {
name: add_pool.name,
symbol: add_pool.symbol,
coins: add_pool.coins,
a: add_pool.a,
fee: add_pool.fee,
asset_type: add_pool.asset_type,
implementation_idx: BigInt::from(0),
}
})
})
.or_else(|| {
abi::meta_pool_factory::functions::DeployPlainPool3::match_and_decode(
call,
)
})?;
// The return data of several of these calls contain the actual component id
let component_id = &call.return_data[12..];
Some(ProtocolComponent {
id: hex::encode(component_id),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: pool_added
.coins
.into_iter()
.filter(|token| *token != [0; 20])
.collect(),
contracts: vec![component_id.into()],
static_att: vec![
Attribute {
name: "pool_type".into(),
value: "PlainPool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "name".into(),
value: add_pool.name.into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory_name".into(),
value: "meta_pool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory".into(),
value: address_to_bytes_with_0x(&META_POOL_FACTORY),
change: ChangeType::Creation.into(),
},
],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
})
} else if let Some(pool_added) =
abi::meta_pool_factory::events::MetaPoolDeployed::match_and_decode(log)
{
let add_pool =
abi::meta_pool_factory::functions::DeployMetapool1::match_and_decode(call)
.map(|add_pool| abi::meta_pool_factory::functions::DeployMetapool2 {
base_pool: add_pool.base_pool,
name: add_pool.name,
symbol: add_pool.symbol,
coin: add_pool.coin,
a: add_pool.a,
fee: add_pool.fee,
implementation_idx: BigInt::from(0),
})
.or_else(|| {
abi::meta_pool_factory::functions::DeployMetapool2::match_and_decode(
call,
)
})?;
let component_id = &call.return_data[12..];
// The `add_pool.base_pool` may only refer to the contract of the base pool and not
// the token itself. This means we **have** to make an RPC call to the
// `meta_registry` in order to get the real LP token address.
let get_lp_token =
abi::meta_registry::functions::GetLpToken1 { pool: add_pool.base_pool.clone() };
let lp_token = get_lp_token.call(META_REGISTRY.to_vec())?;
Some(ProtocolComponent {
id: hex::encode(component_id),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: vec![pool_added.coin, lp_token],
contracts: vec![component_id.into()],
static_att: vec![
Attribute {
name: "pool_type".into(),
value: "metapool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "name".into(),
value: add_pool.name.into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory_name".into(),
value: "meta_pool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory".into(),
value: address_to_bytes_with_0x(&META_POOL_FACTORY),
change: ChangeType::Creation.into(),
},
Attribute {
name: "base_pool".into(),
value: address_to_bytes_with_0x(
&add_pool.base_pool.try_into().unwrap(),
),
change: ChangeType::Creation.into(),
},
],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
})
} else {
None
}
}
META_POOL_FACTORY_OLD => {
if let Some(pool_added) =
abi::meta_pool_factory::events::MetaPoolDeployed::match_and_decode(log)
{
let add_pool =
abi::meta_pool_factory::functions::DeployMetapool1::match_and_decode(call)
.map(|add_pool| abi::meta_pool_factory::functions::DeployMetapool2 {
base_pool: add_pool.base_pool,
name: add_pool.name,
symbol: add_pool.symbol,
coin: add_pool.coin,
a: add_pool.a,
fee: add_pool.fee,
implementation_idx: BigInt::from(0),
})
.or_else(|| {
abi::meta_pool_factory::functions::DeployMetapool2::match_and_decode(
call,
)
})?;
let component_id = &call.return_data[12..];
let lp_token = get_token_from_pool(&pool_added.base_pool);
Some(ProtocolComponent {
id: hex::encode(component_id),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: vec![pool_added.coin, lp_token],
contracts: vec![component_id.into()],
static_att: vec![
Attribute {
name: "pool_type".into(),
value: "metapool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "name".into(),
value: add_pool.name.into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory_name".into(),
value: "meta_pool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory".into(),
value: address_to_bytes_with_0x(&META_POOL_FACTORY),
change: ChangeType::Creation.into(),
},
Attribute {
name: "base_pool".into(),
value: address_to_bytes_with_0x(
&add_pool.base_pool.try_into().unwrap(),
),
change: ChangeType::Creation.into(),
},
],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
})
} else {
None
}
}
CRYPTO_SWAP_NG_FACTORY => {
if let Some(pool_added) =
abi::crypto_swap_ng_factory::events::PlainPoolDeployed::match_and_decode(log)
{
let add_pool =
abi::crypto_swap_ng_factory::functions::DeployPlainPool::match_and_decode(
call,
)?;
let component_id = &call.return_data[12..];
Some(ProtocolComponent {
id: hex::encode(component_id),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: pool_added.coins,
contracts: vec![component_id.into()],
static_att: vec![
Attribute {
name: "pool_type".into(),
value: "plain_pool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "name".into(),
value: add_pool.name.into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory_name".into(),
value: "crypto_swap_ng".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory".into(),
value: address_to_bytes_with_0x(&CRYPTO_SWAP_NG_FACTORY),
change: ChangeType::Creation.into(),
},
],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
})
} else if let Some(pool_added) =
abi::crypto_swap_ng_factory::events::MetaPoolDeployed::match_and_decode(log)
{
let add_pool =
abi::crypto_swap_ng_factory::functions::DeployMetapool::match_and_decode(call)?;
let component_id = &call.return_data[12..];
let lp_token = get_token_from_pool(&pool_added.base_pool);
Some(ProtocolComponent {
id: hex::encode(component_id),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: vec![pool_added.coin, lp_token],
contracts: vec![component_id.into()],
static_att: vec![
Attribute {
name: "pool_type".into(),
value: "metapool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "name".into(),
value: add_pool.name.into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory_name".into(),
value: "crypto_swap_ng".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory".into(),
value: address_to_bytes_with_0x(&CRYPTO_SWAP_NG_FACTORY),
change: ChangeType::Creation.into(),
},
Attribute {
name: "base_pool".into(),
value: address_to_bytes_with_0x(
&pool_added.base_pool.try_into().unwrap(),
),
change: ChangeType::Creation.into(),
},
],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
})
} else {
None
}
}
TRICRYPTO_FACTORY => {
if let Some(pool_added) =
abi::tricrypto_factory::events::TricryptoPoolDeployed::match_and_decode(log)
{
let tokens = swap_weth_for_eth(pool_added.coins.into());
Some(ProtocolComponent {
id: hex::encode(&pool_added.pool),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens,
contracts: vec![pool_added.pool],
static_att: vec![
Attribute {
name: "pool_type".into(),
value: "trycrypto".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "name".into(),
value: pool_added.name.into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory_name".into(),
value: "tricrypto".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory".into(),
value: address_to_bytes_with_0x(&TRICRYPTO_FACTORY),
change: ChangeType::Creation.into(),
},
],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
})
} else {
None
}
}
STABLESWAP_FACTORY => {
if let Some(pool_added) =
abi::stableswap_factory::events::PlainPoolDeployed::match_and_decode(log)
{
let add_pool = if let Some(pool) =
abi::stableswap_factory::functions::DeployPlainPool1::match_and_decode(call)
{
abi::stableswap_factory::functions::DeployPlainPool3 {
name: pool.name,
symbol: pool.symbol,
coins: pool.coins,
a: pool.a,
fee: pool.fee,
asset_type: BigInt::from(0),
implementation_idx: BigInt::from(0),
}
} else if let Some(pool) =
abi::stableswap_factory::functions::DeployPlainPool2::match_and_decode(call)
{
abi::stableswap_factory::functions::DeployPlainPool3 {
name: pool.name,
symbol: pool.symbol,
coins: pool.coins,
a: pool.a,
fee: pool.fee,
asset_type: BigInt::from(0),
implementation_idx: BigInt::from(0),
}
} else if let Some(pool) =
abi::stableswap_factory::functions::DeployPlainPool3::match_and_decode(call)
{
pool
} else {
return None;
};
let component_id = &call.return_data[12..];
Some(ProtocolComponent {
id: hex::encode(component_id),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: pool_added.coins.into(),
contracts: vec![component_id.into()],
static_att: vec![
Attribute {
name: "pool_type".into(),
value: "plain".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "name".into(),
value: add_pool.name.into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory_name".into(),
value: "stable_swap".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory".into(),
value: address_to_bytes_with_0x(&CRYPTO_SWAP_NG_FACTORY),
change: ChangeType::Creation.into(),
},
],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
})
} else if let Some(pool_added) =
abi::stableswap_factory::events::MetaPoolDeployed::match_and_decode(log)
{
let add_pool = if let Some(pool) =
abi::stableswap_factory::functions::DeployMetapool1::match_and_decode(call)
{
abi::stableswap_factory::functions::DeployMetapool2 {
base_pool: pool.base_pool,
name: pool.name,
symbol: pool.symbol,
coin: pool.coin,
a: pool.a,
fee: pool.fee,
implementation_idx: BigInt::from(0),
}
} else if let Some(pool) =
abi::stableswap_factory::functions::DeployMetapool2::match_and_decode(call)
{
pool
} else {
return None;
};
let component_id = &call.return_data[12..];
let get_lp_token =
abi::meta_registry::functions::GetLpToken1 { pool: add_pool.base_pool.clone() };
let lp_token = get_lp_token.call(META_REGISTRY.to_vec())?;
Some(ProtocolComponent {
id: hex::encode(component_id),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: vec![pool_added.coin, lp_token],
contracts: vec![component_id.into()],
static_att: vec![
Attribute {
name: "pool_type".into(),
value: "metapool".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "name".into(),
value: add_pool.name.into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory_name".into(),
value: "stable_swap".into(),
change: ChangeType::Creation.into(),
},
Attribute {
name: "factory".into(),
value: address_to_bytes_with_0x(&STABLESWAP_FACTORY),
change: ChangeType::Creation.into(),
},
Attribute {
name: "base_pool".into(),
value: address_to_bytes_with_0x(
&pool_added.base_pool.try_into().unwrap(),
),
change: ChangeType::Creation.into(),
},
],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
})
} else {
None
}
}
_ => None,
}
}
/// This function makes 3 attempts to confirm / get the LP token address from a pool address.
///
/// 1. We attempt to see if the pool address is a token address itself by calling an ERC 20 func.
/// - Some pools may not be the token themselves
/// 2. Then, we try to ping the `META_REGISTRY` address to see if it has a record of the pool.
/// - Older pools might have been created before the `META_REGISTRY` was created and therefore
/// would have registered much later
/// 3. Finally, we have a hardcoded map of pool address -> token address for some pools.
///
/// If all else fails, we force an `unwrap` to trigger a `panic` so that we can resolve this by
/// adding onto our map of `pool` -> `token` addresses.
fn get_token_from_pool(pool: &Vec<u8>) -> Vec<u8> {
abi::erc20::functions::Name {}
.call(pool.clone())
.and(Some(pool.clone()))
.or_else(|| {
abi::meta_registry::functions::GetLpToken1 { pool: pool.clone() }
.call(META_REGISTRY.to_vec())
})
.or_else(|| {
match hex::encode(pool).as_str() {
// Curve.fi DAI/USDC/USDT (3Crv)
"bebc44782c7db0a1a60cb6fe97d0b483032ff1c7" => {
hex::decode("6c3F90f043a72FA612cbac8115EE7e52BDe6E490").ok()
}
// Placeholder if we can't find the token. It will help us to detect these missing
// token easily with a SQL query.
_ => hex::decode("1111111111111111111111111111111111111111").ok(),
}
})
.unwrap()
}

View File

@@ -0,0 +1,131 @@
use anyhow::{Context, Result};
use serde::Deserialize;
use std::{collections::HashMap, iter::zip};
use substreams_ethereum::pb::eth::v2::TransactionTrace;
use tycho_substreams::prelude::*;
const PARAMS_SEPERATOR: &str = ",";
#[derive(Debug, Deserialize, PartialEq)]
struct PoolQueryParams {
address: String,
tx_hash: String,
tokens: Vec<String>,
attribute_keys: Option<Vec<String>>,
attribute_vals: Option<Vec<String>>,
}
/// This function parses the `params` string and extracts the pool query parameters. `params` are
/// comma-separated, URL-encoded (defined by `serde-qs`) strings, with each component defining the
/// pool query parameters defined in the struct above. We then iterate through the transactions in
/// a block, and then if the transaction hash matches our parameter, we emit a `ProtocolComponent`
/// defined by the metadata from above alongside some basic defaults that we know for Curve.
///
/// Static attributes are defined as a vector of tuples with the name and value of the attribute.
/// These contain things like the pool type, specific pool fees, etc. You can see
/// `pool_factories.rs` for an example of the modern curve pool attributes and also the ones chosen
/// for 3pool, etc.
///
/// This function can error based on some basic parsing errors and deeper down hex decoding errors
/// if various addresses are not formatted properly.
pub fn emit_specific_pools(
params: &str,
tx: &TransactionTrace,
) -> Result<Option<ProtocolComponent>> {
let pools = parse_params(params)?;
create_component(tx, pools)
}
fn create_component(
tx: &TransactionTrace,
pools: HashMap<String, PoolQueryParams>,
) -> Result<Option<ProtocolComponent>> {
let encoded_hash = hex::encode(tx.hash.clone());
if let Some(pool) = pools.get(&encoded_hash) {
Ok(Some(ProtocolComponent {
id: pool.address.clone(),
tx: Some(Transaction {
to: tx.to.clone(),
from: tx.from.clone(),
hash: tx.hash.clone(),
index: tx.index.into(),
}),
tokens: pool
.tokens
.clone()
.into_iter()
.map(|token| Result::Ok(hex::decode(token)?))
.collect::<Result<Vec<_>>>()
.with_context(|| "Token addresses were not formatted properly")?,
static_att: zip(
pool.attribute_keys
.clone()
.unwrap_or(vec![]),
pool.attribute_vals
.clone()
.unwrap_or(vec![]),
)
.clone()
.map(|(key, value)| Attribute {
name: key,
value: value.into(),
change: ChangeType::Creation.into(),
})
.collect::<Vec<_>>(),
contracts: vec![hex::decode(pool.address.clone())
.with_context(|| "Pool address was not formatted properly")?],
change: ChangeType::Creation.into(),
protocol_type: Some(ProtocolType {
name: "curve_pool".into(),
financial_type: FinancialType::Swap.into(),
attribute_schema: Vec::new(),
implementation_type: ImplementationType::Vm.into(),
}),
}))
} else {
Ok(None)
}
}
fn parse_params(params: &str) -> Result<HashMap<String, PoolQueryParams>, anyhow::Error> {
let pools: HashMap<String, PoolQueryParams> = params
.split(PARAMS_SEPERATOR)
.map(|param| {
let pool: PoolQueryParams = serde_qs::from_str(param)
.with_context(|| format!("Failed to parse pool query params: {0}", param))?;
Ok((pool.tx_hash.clone(), pool))
})
.collect::<Result<HashMap<_, _>>>()
.with_context(|| "Failed to parse all pool query params")?;
Ok(pools)
}
mod tests {
#[test]
fn test_parse_params() {
use crate::pools::{parse_params, PoolQueryParams};
use std::collections::HashMap;
// Existing test case
let params = "address=0x5F890841f657d90E081bAbdB532A05996Af79Fe6&tx_hash=0xb71a66c1d93c525a2dd19a8db0da19e65be04f36e733af7f03e3c9dff41aa16a&tokens[]=0x6b175474e89094c44da98b954eedeac495271d0f&tokens[]=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&tokens[]=0xdac17f958d2ee523a2206206994597c13d831ec7&attribute_keys[]=key1&attribute_vals[]=val1".to_string();
let expected_result = {
let mut map = HashMap::new();
map.insert(
"0xb71a66c1d93c525a2dd19a8db0da19e65be04f36e733af7f03e3c9dff41aa16a".to_string(),
PoolQueryParams {
address: "0x5F890841f657d90E081bAbdB532A05996Af79Fe6".to_string(),
tx_hash: "0xb71a66c1d93c525a2dd19a8db0da19e65be04f36e733af7f03e3c9dff41aa16a"
.to_string(),
tokens: vec![
"0x6b175474e89094c44da98b954eedeac495271d0f".to_string(),
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48".to_string(),
"0xdac17f958d2ee523a2206206994597c13d831ec7".to_string(),
],
attribute_keys: Some(vec!["key1".to_string()]),
attribute_vals: Some(vec!["val1".to_string()]),
},
);
map
};
assert_eq!(parse_params(&params).unwrap(), expected_result);
}
}

View File

@@ -0,0 +1,66 @@
specVersion: v0.1.0
package:
name: "substreams_curve"
version: v0.1.0
protobuf:
files:
- tycho/evm/v1/vm.proto
- tycho/evm/v1/common.proto
- tycho/evm/v1/utils.proto
importPaths:
- ../../proto
- ./proto
binaries:
default:
type: wasm/rust-v1
file: ../target/wasm32-unknown-unknown/release/ethereum_curve.wasm
modules:
- name: map_components
kind: map
initialBlock: 9906598
inputs:
- params: string
- source: sf.ethereum.type.v2.Block
output:
type: proto:tycho.evm.v1.BlockTransactionProtocolComponents
- name: store_component_tokens
kind: store
initialBlock: 9906598
updatePolicy: set
valueType: string
inputs:
- map: map_components
- name: map_relative_balances
kind: map
initialBlock: 9906598 # An arbitrary block that should change based on your requirements
inputs:
- source: sf.ethereum.type.v2.Block
- store: store_component_tokens
output:
type: proto:tycho.evm.v1.BlockBalanceDeltas
- name: store_balances
kind: store
initialBlock: 9906598
updatePolicy: add
valueType: bigint
inputs:
- map: map_relative_balances
- name: map_protocol_changes
kind: map
initialBlock: 9906598
inputs:
- source: sf.ethereum.type.v2.Block
- map: map_components
- map: map_relative_balances
- store: store_component_tokens
- store: store_balances
mode: deltas # This is the key property that simplifies `BalanceChange` handling
output:
type: proto:tycho.evm.v1.BlockContractChanges

View File

@@ -11,4 +11,5 @@ chain_width = 40
ignore = [
"crates/tycho-substreams/src/pb",
"ethereum-balancer/src/abi",
]
"ethereum-curve/src/abi",
]