refactor(substreams): Update ambient Substreams
This commit is contained in:
83
substreams/ethereum-ambient/src/contracts/hotproxy.rs
Normal file
83
substreams/ethereum-ambient/src/contracts/hotproxy.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use anyhow::{anyhow, bail};
|
||||
|
||||
use crate::utils::{decode_flows_from_output, encode_pool_hash};
|
||||
use ethabi::{decode, ParamType};
|
||||
use hex_literal::hex;
|
||||
use substreams_ethereum::pb::eth::v2::Call;
|
||||
|
||||
pub const AMBIENT_HOTPROXY_CONTRACT: [u8; 20] = hex!("37e00522Ce66507239d59b541940F99eA19fF81F");
|
||||
pub const USER_CMD_HOTPROXY_FN_SIG: [u8; 4] = hex!("f96dc788");
|
||||
|
||||
pub const SWAP_ABI_HOTPROXY_INPUT: &[ParamType] = &[
|
||||
ParamType::Address, // base
|
||||
ParamType::Address, // quote
|
||||
ParamType::Uint(256), // pool index
|
||||
// isBuy - if true the direction of the swap is for the user to send base
|
||||
// tokens and receive back quote tokens.
|
||||
ParamType::Bool,
|
||||
ParamType::Bool, // inBaseQty
|
||||
ParamType::Uint(128), //qty
|
||||
ParamType::Uint(16), // poolTip
|
||||
ParamType::Uint(128), // limitPrice
|
||||
ParamType::Uint(128), // minOut
|
||||
ParamType::Uint(8), // reserveFlags
|
||||
];
|
||||
const USER_CMD_EXTERNAL_ABI: &[ParamType] = &[
|
||||
ParamType::Bytes, // userCmd
|
||||
];
|
||||
|
||||
pub fn decode_direct_swap_hotproxy_call(
|
||||
call: &Call,
|
||||
) -> Result<([u8; 32], ethabi::Int, ethabi::Int), anyhow::Error> {
|
||||
if let Ok(external_cmd) = decode(USER_CMD_EXTERNAL_ABI, &call.input[4..]) {
|
||||
let input_bytes = external_cmd[0]
|
||||
.to_owned()
|
||||
.into_bytes() // Convert Bytes32 to Vec<u8>
|
||||
.ok_or_else(|| anyhow!("Failed to hotproxy userCmd input data.".to_string()))?;
|
||||
|
||||
if let Ok(input_params) = decode(SWAP_ABI_HOTPROXY_INPUT, &input_bytes) {
|
||||
let base_token = input_params[0]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Failed to convert base token to address for direct swap hotproxy call: {:?}",
|
||||
&input_params[0]
|
||||
)
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
|
||||
let quote_token = input_params[1]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Failed to convert quote token to address for direct swap hotproxy call: {:?}",
|
||||
&input_params[1]
|
||||
)
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
|
||||
let mut pool_index_buf = [0u8; 32];
|
||||
input_params[2]
|
||||
.to_owned()
|
||||
.into_uint()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert pool index to u32 for direct swap hotproxy call"
|
||||
.to_string())
|
||||
})?
|
||||
.to_big_endian(&mut pool_index_buf);
|
||||
let pool_index = pool_index_buf.to_vec();
|
||||
|
||||
let (base_flow, quote_flow) = decode_flows_from_output(call)?;
|
||||
let pool_hash = encode_pool_hash(base_token, quote_token, pool_index);
|
||||
Ok((pool_hash, base_flow, quote_flow))
|
||||
} else {
|
||||
bail!("Failed to decode hotproxy swap call internap inputs.".to_string());
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to decode hotproxy swap call external input.".to_string());
|
||||
}
|
||||
}
|
||||
106
substreams/ethereum-ambient/src/contracts/knockout.rs
Normal file
106
substreams/ethereum-ambient/src/contracts/knockout.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use anyhow::{anyhow, bail};
|
||||
|
||||
use crate::utils::{decode_flows_from_output, encode_pool_hash};
|
||||
use ethabi::{decode, ParamType};
|
||||
use hex_literal::hex;
|
||||
use substreams_ethereum::pb::eth::v2::Call;
|
||||
|
||||
pub const AMBIENT_KNOCKOUT_CONTRACT: [u8; 20] = hex!("7F5D75AdE75646919c923C98D53E9Cc7Be7ea794");
|
||||
pub const USER_CMD_KNOCKOUT_FN_SIG: [u8; 4] = hex!("f96dc788");
|
||||
|
||||
// Represents the ABI of any cmd which is not mint or burn
|
||||
const KNOCKOUT_INTERNAL_OTHER_CMD_ABI: &[ParamType] = &[
|
||||
ParamType::Uint(8),
|
||||
ParamType::Address, // base
|
||||
ParamType::Address, // quote
|
||||
ParamType::Uint(256), // poolIdx
|
||||
ParamType::Int(24),
|
||||
ParamType::Int(24),
|
||||
ParamType::Bool,
|
||||
ParamType::Uint(8),
|
||||
ParamType::Uint(256),
|
||||
ParamType::Uint(256),
|
||||
ParamType::Uint(32),
|
||||
];
|
||||
const KNOCKOUT_INTERNAL_MINT_BURN_ABI: &[ParamType] = &[
|
||||
ParamType::Uint(8),
|
||||
ParamType::Address, // base
|
||||
ParamType::Address, // quote
|
||||
ParamType::Uint(256), // poolIdx
|
||||
ParamType::Int(24),
|
||||
ParamType::Int(24),
|
||||
ParamType::Bool,
|
||||
ParamType::Uint(8),
|
||||
ParamType::Uint(256),
|
||||
ParamType::Uint(256),
|
||||
ParamType::Uint(128),
|
||||
ParamType::Bool,
|
||||
];
|
||||
|
||||
const KNOCKOUT_EXTERNAL_ABI: &[ParamType] = &[
|
||||
ParamType::Bytes, // userCmd
|
||||
];
|
||||
|
||||
pub fn decode_knockout_call(
|
||||
call: &Call,
|
||||
) -> Result<([u8; 32], ethabi::Int, ethabi::Int), anyhow::Error> {
|
||||
if let Ok(external_cmd) = decode(KNOCKOUT_EXTERNAL_ABI, &call.input[4..]) {
|
||||
let input_data = external_cmd[0]
|
||||
.to_owned()
|
||||
.into_bytes() // Convert Bytes32 to Vec<u8>
|
||||
.ok_or_else(|| anyhow!("Failed to Knockout userCmd input data.".to_string()))?;
|
||||
|
||||
let code = input_data[31];
|
||||
let is_mint = code == 91;
|
||||
let is_burn = code == 92;
|
||||
|
||||
let abi = if is_mint || is_burn {
|
||||
KNOCKOUT_INTERNAL_MINT_BURN_ABI
|
||||
} else {
|
||||
KNOCKOUT_INTERNAL_OTHER_CMD_ABI
|
||||
};
|
||||
|
||||
if let Ok(mint_burn_inputs) = decode(abi, &input_data) {
|
||||
let base_token = mint_burn_inputs[1]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Failed to convert base token to address for knockout call: {:?}",
|
||||
&mint_burn_inputs[1]
|
||||
)
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
let quote_token = mint_burn_inputs[2]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Failed to convert quote token to address for knockout call: {:?}",
|
||||
&mint_burn_inputs[2]
|
||||
)
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
|
||||
let mut pool_index_buf = [0u8; 32];
|
||||
mint_burn_inputs[3]
|
||||
.to_owned()
|
||||
.into_uint()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert pool index to bytes for knockout call".to_string())
|
||||
})?
|
||||
.to_big_endian(&mut pool_index_buf);
|
||||
let pool_index = pool_index_buf.to_vec();
|
||||
|
||||
let (base_flow, quote_flow) = decode_flows_from_output(call)?;
|
||||
let pool_hash = encode_pool_hash(base_token, quote_token, pool_index);
|
||||
Ok((pool_hash, base_flow, quote_flow))
|
||||
} else {
|
||||
bail!("Failed to decode knockout call outputs.".to_string());
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to decode inputs for knockout call.".to_string());
|
||||
}
|
||||
}
|
||||
170
substreams/ethereum-ambient/src/contracts/main.rs
Normal file
170
substreams/ethereum-ambient/src/contracts/main.rs
Normal file
@@ -0,0 +1,170 @@
|
||||
use anyhow::{anyhow, bail};
|
||||
use tycho_substreams::models::{
|
||||
Attribute, ChangeType, FinancialType, ImplementationType, ProtocolComponent, ProtocolType,
|
||||
Transaction,
|
||||
};
|
||||
|
||||
use crate::utils::{decode_flows_from_output, encode_pool_hash};
|
||||
use ethabi::{decode, ParamType};
|
||||
use hex_literal::hex;
|
||||
use substreams_ethereum::pb::eth::v2::Call;
|
||||
|
||||
pub const AMBIENT_CONTRACT: [u8; 20] = hex!("aaaaaaaaa24eeeb8d57d431224f73832bc34f688");
|
||||
pub const USER_CMD_FN_SIG: [u8; 4] = hex!("a15112f9");
|
||||
|
||||
const USER_CMD_EXTERNAL_ABI: &[ParamType] = &[
|
||||
// index of the proxy sidecar the command is being called on
|
||||
ParamType::Uint(16),
|
||||
// call data for internal UserCmd method
|
||||
ParamType::Bytes,
|
||||
];
|
||||
const USER_CMD_INTERNAL_ABI: &[ParamType] = &[
|
||||
ParamType::Uint(8), // command
|
||||
ParamType::Address, // base
|
||||
ParamType::Address, // quote
|
||||
ParamType::Uint(256), // pool index
|
||||
ParamType::Uint(128), // price
|
||||
];
|
||||
|
||||
pub const INIT_POOL_CODE: u8 = 71;
|
||||
|
||||
pub const SWAP_ABI_INPUT: &[ParamType] = &[
|
||||
ParamType::Address, // base
|
||||
ParamType::Address, // quote
|
||||
ParamType::Uint(256), // pool index
|
||||
// isBuy - if true the direction of the swap is for the user to send base
|
||||
// tokens and receive back quote tokens.
|
||||
ParamType::Bool,
|
||||
ParamType::Bool, // inBaseQty
|
||||
ParamType::Uint(128), //qty
|
||||
ParamType::Uint(16), // poolTip
|
||||
ParamType::Uint(128), // limitPrice
|
||||
ParamType::Uint(128), // minOut
|
||||
ParamType::Uint(8), // reserveFlags
|
||||
];
|
||||
|
||||
// MicroPaths fn sigs
|
||||
pub const SWAP_FN_SIG: [u8; 4] = hex!("3d719cd9");
|
||||
|
||||
pub fn decode_direct_swap_call(
|
||||
call: &Call,
|
||||
) -> Result<([u8; 32], ethabi::Int, ethabi::Int), anyhow::Error> {
|
||||
if let Ok(external_input_params) = decode(SWAP_ABI_INPUT, &call.input[4..]) {
|
||||
let base_token = external_input_params[0]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Failed to convert base token to address for direct swap call: {:?}",
|
||||
&external_input_params[0]
|
||||
)
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
|
||||
let quote_token = external_input_params[1]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Failed to convert quote token to address for direct swap call: {:?}",
|
||||
&external_input_params[1]
|
||||
)
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
|
||||
let mut pool_index_buf = [0u8; 32];
|
||||
external_input_params[2]
|
||||
.to_owned()
|
||||
.into_uint()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert pool index to u32 for direct swap call".to_string())
|
||||
})?
|
||||
.to_big_endian(&mut pool_index_buf);
|
||||
let pool_index = pool_index_buf.to_vec();
|
||||
|
||||
let (base_flow, quote_flow) = decode_flows_from_output(call)?;
|
||||
let pool_hash = encode_pool_hash(base_token, quote_token, pool_index);
|
||||
Ok((pool_hash, base_flow, quote_flow))
|
||||
} else {
|
||||
bail!("Failed to decode swap call inputs.".to_string());
|
||||
}
|
||||
}
|
||||
pub fn decode_pool_init(
|
||||
call: &Call,
|
||||
tx: Transaction,
|
||||
) -> Result<Option<ProtocolComponent>, anyhow::Error> {
|
||||
// Decode external call to UserCmd
|
||||
if let Ok(external_params) = decode(USER_CMD_EXTERNAL_ABI, &call.input[4..]) {
|
||||
let cmd_bytes = external_params[1]
|
||||
.to_owned()
|
||||
.into_bytes()
|
||||
.ok_or_else(|| anyhow!("Failed to convert to bytes: {:?}", &external_params[1]))?;
|
||||
|
||||
// Call data is structured differently depending on the cmd code, so only
|
||||
// decode if this is an init pool code.
|
||||
if cmd_bytes[31] == INIT_POOL_CODE {
|
||||
// Decode internal call to UserCmd
|
||||
if let Ok(internal_params) = decode(USER_CMD_INTERNAL_ABI, &cmd_bytes) {
|
||||
let base = internal_params[1]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert to address: {:?}", &internal_params[1])
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
|
||||
let quote = internal_params[2]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert to address: {:?}", &internal_params[2])
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
|
||||
let mut pool_index_buf = [0u8; 32];
|
||||
internal_params[3]
|
||||
.to_owned()
|
||||
.into_uint()
|
||||
.ok_or_else(|| anyhow!("Failed to convert to u32".to_string()))?
|
||||
.to_big_endian(&mut pool_index_buf);
|
||||
let pool_index = pool_index_buf.to_vec();
|
||||
let pool_hash = encode_pool_hash(base.clone(), quote.clone(), pool_index.clone());
|
||||
|
||||
let static_attribute = Attribute {
|
||||
name: String::from("pool_index"),
|
||||
value: pool_index,
|
||||
change: ChangeType::Creation.into(),
|
||||
};
|
||||
|
||||
let mut tokens: Vec<Vec<u8>> = vec![base.clone(), quote.clone()];
|
||||
tokens.sort();
|
||||
|
||||
let new_component = ProtocolComponent {
|
||||
id: hex::encode(pool_hash),
|
||||
tokens,
|
||||
contracts: vec![AMBIENT_CONTRACT.to_vec()],
|
||||
static_att: vec![static_attribute],
|
||||
change: ChangeType::Creation.into(),
|
||||
protocol_type: Some(ProtocolType {
|
||||
name: "ambient_pool".to_string(),
|
||||
attribute_schema: vec![],
|
||||
financial_type: FinancialType::Swap.into(),
|
||||
implementation_type: ImplementationType::Vm.into(),
|
||||
}),
|
||||
tx: Some(tx.clone()),
|
||||
};
|
||||
Ok(Some(new_component))
|
||||
} else {
|
||||
bail!("Failed to decode ABI internal call.".to_string());
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to decode ABI external call.".to_string());
|
||||
}
|
||||
}
|
||||
307
substreams/ethereum-ambient/src/contracts/micropaths.rs
Normal file
307
substreams/ethereum-ambient/src/contracts/micropaths.rs
Normal file
@@ -0,0 +1,307 @@
|
||||
use anyhow::{anyhow, bail};
|
||||
|
||||
use ethabi::{decode, ParamType};
|
||||
use hex_literal::hex;
|
||||
use substreams_ethereum::pb::eth::v2::Call;
|
||||
|
||||
pub const AMBIENT_MICROPATHS_CONTRACT: [u8; 20] = hex!("f241bEf0Ea64020655C70963ef81Fea333752367");
|
||||
|
||||
pub const SWEEP_SWAP_FN_SIG: [u8; 4] = hex!("7b370fc2");
|
||||
|
||||
pub const MINT_AMBIENT_FN_SIG: [u8; 4] = hex!("2ee11587");
|
||||
pub const MINT_RANGE_FN_SIG: [u8; 4] = hex!("2370632b");
|
||||
pub const BURN_AMBIENT_FN_SIG: [u8; 4] = hex!("2a6f0864");
|
||||
pub const BURN_RANGE_FN_SIG: [u8; 4] = hex!("7c6dfe3d");
|
||||
|
||||
// ABI for the mintAmbient function with return values
|
||||
pub const MINT_AMBIENT_RETURN_ABI: &[ParamType] = &[
|
||||
ParamType::Int(128), // int128 baseFlow
|
||||
ParamType::Int(128), // int128 quoteFlow
|
||||
ParamType::Uint(128), // uint128 seedOut
|
||||
];
|
||||
|
||||
// ABI for the mintAmbient function parameters
|
||||
const MINT_AMBIENT_ABI: &[ParamType] = &[
|
||||
ParamType::Uint(128), // uint128 price
|
||||
ParamType::Uint(128), // uint128 seed
|
||||
ParamType::Uint(128), // uint128 conc
|
||||
ParamType::Uint(64), // uint64 seedGrowth
|
||||
ParamType::Uint(64), // uint64 concGrowth
|
||||
ParamType::Uint(128), // uint128 liq
|
||||
ParamType::FixedBytes(32), // bytes32 poolHash
|
||||
];
|
||||
|
||||
// ABI for the burnRange function
|
||||
const BURN_RANGE_ABI: &[ParamType] = &[
|
||||
ParamType::Uint(128), // price
|
||||
ParamType::Int(24), // priceTick
|
||||
ParamType::Uint(128), // seed
|
||||
ParamType::Uint(128), // conc
|
||||
ParamType::Uint(64), // seedGrowth
|
||||
ParamType::Uint(64), // concGrowth
|
||||
ParamType::Int(24), // lowTick
|
||||
ParamType::Int(24), // highTick
|
||||
ParamType::Uint(128), // liq
|
||||
ParamType::FixedBytes(32), // poolHash
|
||||
];
|
||||
|
||||
const BURN_RANGE_RETURN_ABI: &[ParamType] = &[
|
||||
ParamType::Int(128), // baseFlow
|
||||
ParamType::Int(128), // quoteFlow
|
||||
ParamType::Uint(128), // seedOut
|
||||
ParamType::Uint(128), // concOut
|
||||
];
|
||||
|
||||
// ABI for the burnAmbient function with return values
|
||||
const BURN_AMBIENT_RETURN_ABI: &[ParamType] = &[
|
||||
ParamType::Int(128), // int128 baseFlow
|
||||
ParamType::Int(128), // int128 quoteFlow
|
||||
ParamType::Uint(128), // uint128 seedOut
|
||||
];
|
||||
|
||||
// ABI for the burnAmbient function
|
||||
const BURN_AMBIENT_ABI: &[ParamType] = &[
|
||||
ParamType::Uint(128), // uint128 price
|
||||
ParamType::Uint(128), // uint128 seed
|
||||
ParamType::Uint(128), // uint128 conc
|
||||
ParamType::Uint(64), // uint64 seedGrowth
|
||||
ParamType::Uint(64), // uint64 concGrowth
|
||||
ParamType::Uint(128), // uint128 liq
|
||||
ParamType::FixedBytes(32), // bytes32 poolHash
|
||||
];
|
||||
|
||||
// ABI for the mintRange function parameters
|
||||
const MINT_RANGE_ABI: &[ParamType] = &[
|
||||
ParamType::Uint(128), // price
|
||||
ParamType::Int(24), // priceTick
|
||||
ParamType::Uint(128), // seed
|
||||
ParamType::Uint(128), // conc
|
||||
ParamType::Uint(64), // seedGrowth
|
||||
ParamType::Uint(64), // concGrowth
|
||||
ParamType::Int(24), // lowTick
|
||||
ParamType::Int(24), // highTick
|
||||
ParamType::Uint(128), // liq
|
||||
ParamType::FixedBytes(32), // poolHash
|
||||
];
|
||||
|
||||
// ABI for the mintRange function with return values
|
||||
const MINT_RANGE_RETURN_ABI: &[ParamType] = &[
|
||||
ParamType::Int(128), // baseFlow
|
||||
ParamType::Int(128), // quoteFlow
|
||||
ParamType::Uint(128), // seedOut
|
||||
ParamType::Uint(128), // concOut
|
||||
];
|
||||
pub fn decode_mint_range_call(
|
||||
call: &Call,
|
||||
) -> Result<([u8; 32], ethabi::Int, ethabi::Int), anyhow::Error> {
|
||||
if let Ok(mint_range) = decode(MINT_RANGE_ABI, &call.input[4..]) {
|
||||
let pool_hash: [u8; 32] = mint_range[9]
|
||||
.to_owned()
|
||||
.into_fixed_bytes()
|
||||
.ok_or_else(|| anyhow!("Failed to convert pool hash to fixed bytes".to_string()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
if let Ok(external_outputs) = decode(MINT_RANGE_RETURN_ABI, &call.return_data) {
|
||||
let base_flow = external_outputs[0]
|
||||
.to_owned()
|
||||
.into_int() // Needs conversion into bytes for next step
|
||||
.ok_or_else(|| anyhow!("Failed to convert base flow to i128".to_string()))?;
|
||||
|
||||
let quote_flow = external_outputs[1]
|
||||
.to_owned()
|
||||
.into_int() // Needs conversion into bytes for next step
|
||||
.ok_or_else(|| anyhow!("Failed to convert quote flow to i128".to_string()))?;
|
||||
Ok((pool_hash, base_flow, quote_flow))
|
||||
} else {
|
||||
bail!("Failed to decode swap call outputs.".to_string());
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to decode inputs for WarmPath userCmd call.".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_burn_ambient_call(
|
||||
call: &Call,
|
||||
) -> Result<([u8; 32], ethabi::Int, ethabi::Int), anyhow::Error> {
|
||||
if let Ok(burn_ambient) = decode(BURN_AMBIENT_ABI, &call.input[4..]) {
|
||||
let pool_hash: [u8; 32] = burn_ambient[6]
|
||||
.to_owned()
|
||||
.into_fixed_bytes()
|
||||
.ok_or_else(|| anyhow!("Failed to convert pool hash to bytes".to_string()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
if let Ok(external_outputs) = decode(BURN_AMBIENT_RETURN_ABI, &call.return_data) {
|
||||
let base_flow = external_outputs[0]
|
||||
.to_owned()
|
||||
.into_int()
|
||||
.ok_or_else(|| anyhow!("Failed to convert base flow to i128".to_string()))?;
|
||||
|
||||
let quote_flow = external_outputs[1]
|
||||
.to_owned()
|
||||
.into_int()
|
||||
.ok_or_else(|| anyhow!("Failed to convert quote flow to i128".to_string()))?;
|
||||
|
||||
Ok((pool_hash, base_flow, quote_flow))
|
||||
} else {
|
||||
bail!("Failed to decode burnAmbient call outputs.".to_string());
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to decode inputs for burnAmbient call.".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_mint_ambient_call(
|
||||
call: &Call,
|
||||
) -> Result<([u8; 32], ethabi::Int, ethabi::Int), anyhow::Error> {
|
||||
if let Ok(mint_ambient) = decode(MINT_AMBIENT_ABI, &call.input[4..]) {
|
||||
let pool_hash: [u8; 32] = mint_ambient[6]
|
||||
.to_owned()
|
||||
.into_fixed_bytes()
|
||||
.ok_or_else(|| anyhow!("Failed to convert pool hash to bytes".to_string()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
if let Ok(external_outputs) = decode(MINT_AMBIENT_RETURN_ABI, &call.return_data) {
|
||||
let base_flow = external_outputs[0]
|
||||
.to_owned()
|
||||
.into_int()
|
||||
.ok_or_else(|| anyhow!("Failed to convert base flow to i128".to_string()))?;
|
||||
|
||||
let quote_flow = external_outputs[1]
|
||||
.to_owned()
|
||||
.into_int()
|
||||
.ok_or_else(|| anyhow!("Failed to convert quote flow to i128".to_string()))?;
|
||||
|
||||
Ok((pool_hash, base_flow, quote_flow))
|
||||
} else {
|
||||
bail!("Failed to decode mintAmbient call outputs.".to_string());
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to decode inputs for mintAmbient call.".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_burn_range_call(
|
||||
call: &Call,
|
||||
) -> Result<([u8; 32], ethabi::Int, ethabi::Int), anyhow::Error> {
|
||||
if let Ok(burn_range) = decode(BURN_RANGE_ABI, &call.input[4..]) {
|
||||
let pool_hash: [u8; 32] = burn_range[9]
|
||||
.to_owned()
|
||||
.into_fixed_bytes() // Convert Bytes32 to Vec<u8>
|
||||
.ok_or_else(|| anyhow!("Failed to convert pool hash to bytes".to_string()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
if let Ok(external_outputs) = decode(BURN_RANGE_RETURN_ABI, &call.return_data) {
|
||||
let base_flow = external_outputs[0]
|
||||
.to_owned()
|
||||
.into_int()
|
||||
.ok_or_else(|| anyhow!("Failed to convert base flow to i128".to_string()))?;
|
||||
|
||||
let quote_flow = external_outputs[1]
|
||||
.to_owned()
|
||||
.into_int()
|
||||
.ok_or_else(|| anyhow!("Failed to convert quote flow to i128".to_string()))?;
|
||||
|
||||
Ok((pool_hash, base_flow, quote_flow))
|
||||
} else {
|
||||
bail!("Failed to decode burnRange call outputs.".to_string());
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to decode inputs for burnRange call.".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_sweep_swap_call(
|
||||
call: &Call,
|
||||
) -> Result<([u8; 32], ethabi::Int, ethabi::Int), anyhow::Error> {
|
||||
let sweep_swap_abi: &[ParamType] = &[
|
||||
ParamType::Tuple(vec![
|
||||
ParamType::Uint(128),
|
||||
ParamType::Uint(128),
|
||||
ParamType::Uint(128),
|
||||
ParamType::Uint(64),
|
||||
ParamType::Uint(64),
|
||||
]), // CurveState
|
||||
ParamType::Int(24), // midTick
|
||||
ParamType::Tuple(vec![
|
||||
ParamType::Bool,
|
||||
ParamType::Bool,
|
||||
ParamType::Uint(8),
|
||||
ParamType::Uint(128),
|
||||
ParamType::Uint(128),
|
||||
]), // SwapDirective
|
||||
ParamType::Tuple(vec![
|
||||
ParamType::Tuple(vec![
|
||||
ParamType::Uint(8), // schema
|
||||
ParamType::Uint(16), // feeRate
|
||||
ParamType::Uint(8), // protocolTake
|
||||
ParamType::Uint(16), // tickSize
|
||||
ParamType::Uint(8), // jitThresh
|
||||
ParamType::Uint(8), // knockoutBits
|
||||
ParamType::Uint(8), // oracleFlags
|
||||
]),
|
||||
ParamType::FixedBytes(32), // poolHash
|
||||
ParamType::Address,
|
||||
]), // PoolCursor
|
||||
];
|
||||
let sweep_swap_abi_output: &[ParamType] = &[
|
||||
ParamType::Tuple(vec![
|
||||
ParamType::Int(128), // baseFlow
|
||||
ParamType::Int(128), // quoteFlow
|
||||
ParamType::Uint(128),
|
||||
ParamType::Uint(128),
|
||||
]), // Chaining.PairFlow memory accum
|
||||
ParamType::Uint(128), // priceOut
|
||||
ParamType::Uint(128), // seedOut
|
||||
ParamType::Uint(128), // concOut
|
||||
ParamType::Uint(64), // ambientOut
|
||||
ParamType::Uint(64), // concGrowthOut
|
||||
];
|
||||
if let Ok(sweep_swap_input) = decode(sweep_swap_abi, &call.input[4..]) {
|
||||
let pool_cursor = sweep_swap_input[3]
|
||||
.to_owned()
|
||||
.into_tuple()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert pool cursor to tuple for sweepSwap call".to_string())
|
||||
})?;
|
||||
let pool_hash: [u8; 32] = pool_cursor[1]
|
||||
.to_owned()
|
||||
.into_fixed_bytes()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert pool hash to fixed bytes for sweepSwap call".to_string())
|
||||
})?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
if let Ok(sweep_swap_output) = decode(sweep_swap_abi_output, &call.return_data) {
|
||||
let pair_flow = sweep_swap_output[0]
|
||||
.to_owned()
|
||||
.into_tuple()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert pair flow to tuple for sweepSwap call".to_string())
|
||||
})?;
|
||||
|
||||
let base_flow = pair_flow[0]
|
||||
.to_owned()
|
||||
.into_int() // Needs conversion into bytes for next step
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert base flow to i128 for sweepSwap call".to_string())
|
||||
})?;
|
||||
|
||||
let quote_flow = pair_flow[1]
|
||||
.to_owned()
|
||||
.into_int() // Needs conversion into bytes for next step
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert quote flow to i128 for sweepSwap call".to_string())
|
||||
})?;
|
||||
|
||||
Ok((pool_hash, base_flow, quote_flow))
|
||||
} else {
|
||||
bail!("Failed to decode sweepSwap outputs.".to_string());
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to decode sweepSwap inputs.".to_string());
|
||||
}
|
||||
}
|
||||
16
substreams/ethereum-ambient/src/contracts/mod.rs
Normal file
16
substreams/ethereum-ambient/src/contracts/mod.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
// @generated
|
||||
pub mod warmpath {
|
||||
include!("warmpath.rs");
|
||||
}
|
||||
pub mod micropaths {
|
||||
include!("micropaths.rs");
|
||||
}
|
||||
pub mod knockout {
|
||||
include!("knockout.rs");
|
||||
}
|
||||
pub mod hotproxy {
|
||||
include!("hotproxy.rs");
|
||||
}
|
||||
pub mod main {
|
||||
include!("main.rs");
|
||||
}
|
||||
87
substreams/ethereum-ambient/src/contracts/warmpath.rs
Normal file
87
substreams/ethereum-ambient/src/contracts/warmpath.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
use anyhow::{anyhow, bail};
|
||||
|
||||
use crate::utils::{decode_flows_from_output, encode_pool_hash};
|
||||
use ethabi::{decode, ParamType};
|
||||
use hex_literal::hex;
|
||||
use substreams_ethereum::pb::eth::v2::Call;
|
||||
|
||||
pub const AMBIENT_WARMPATH_CONTRACT: [u8; 20] = hex!("d268767BE4597151Ce2BB4a70A9E368ff26cB195");
|
||||
pub const USER_CMD_WARMPATH_FN_SIG: [u8; 4] = hex!("f96dc788");
|
||||
const USER_CMD_EXTERNAL_ABI: &[ParamType] = &[
|
||||
ParamType::Bytes, // userCmd
|
||||
];
|
||||
|
||||
const LIQUIDITY_CHANGE_ABI: &[ParamType] = &[
|
||||
ParamType::Uint(8),
|
||||
ParamType::Address, // base
|
||||
ParamType::Address, // quote
|
||||
ParamType::Uint(256), // pool index
|
||||
ParamType::Int(256),
|
||||
ParamType::Uint(128),
|
||||
ParamType::Uint(128),
|
||||
ParamType::Uint(128),
|
||||
ParamType::Uint(8),
|
||||
ParamType::Address,
|
||||
];
|
||||
pub fn decode_warm_path_user_cmd_call(
|
||||
call: &Call,
|
||||
) -> Result<Option<([u8; 32], ethabi::Int, ethabi::Int)>, anyhow::Error> {
|
||||
if let Ok(external_cmd) = decode(USER_CMD_EXTERNAL_ABI, &call.input[4..]) {
|
||||
let input_bytes = external_cmd[0]
|
||||
.to_owned()
|
||||
.into_bytes() // Convert Bytes32 to Vec<u8>
|
||||
.ok_or_else(|| anyhow!("Failed to hotproxy userCmd input data.".to_string()))?;
|
||||
|
||||
let code = input_bytes[31];
|
||||
let is_mint = [1, 11, 12, 3, 31, 32].contains(&code);
|
||||
let is_burn = [2, 21, 22, 4, 41, 42].contains(&code);
|
||||
let is_harvest = code == 5;
|
||||
if is_mint || is_burn || is_harvest {
|
||||
if let Ok(liquidity_change_calldata) = decode(LIQUIDITY_CHANGE_ABI, &input_bytes) {
|
||||
let base_token = liquidity_change_calldata[1]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Failed to convert base token to address for WarmPath userCmd call: {:?}",
|
||||
&liquidity_change_calldata[1]
|
||||
)
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
let quote_token = liquidity_change_calldata[2]
|
||||
.to_owned()
|
||||
.into_address()
|
||||
.ok_or_else(|| {
|
||||
anyhow!(
|
||||
"Failed to convert quote token to address for WarmPath userCmd call: {:?}",
|
||||
&liquidity_change_calldata[2]
|
||||
)
|
||||
})?
|
||||
.to_fixed_bytes()
|
||||
.to_vec();
|
||||
|
||||
let mut pool_index_buf = [0u8; 32];
|
||||
liquidity_change_calldata[3]
|
||||
.to_owned()
|
||||
.into_uint()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Failed to convert pool index to bytes for WarmPath userCmd call"
|
||||
.to_string())
|
||||
})?
|
||||
.to_big_endian(&mut pool_index_buf);
|
||||
let pool_index = pool_index_buf.to_vec();
|
||||
|
||||
let (base_flow, quote_flow) = decode_flows_from_output(call)?;
|
||||
let pool_hash = encode_pool_hash(base_token, quote_token, pool_index);
|
||||
Ok(Some((pool_hash, base_flow, quote_flow)))
|
||||
} else {
|
||||
bail!("Failed to decode inputs for WarmPath userCmd call.".to_string());
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
bail!("Failed to decode WarmPath call external input.".to_string());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user