fix(balancer): Get all balancer tests working.

This commit is contained in:
kayibal
2024-08-01 12:03:01 +02:00
parent a6cff51bf6
commit 75b66a85af
8 changed files with 187 additions and 150 deletions

View File

@@ -0,0 +1,25 @@
# Balancer Substream
## Open tasks
### Missing rate provider state
Any pool that does use rate providers, is currently not supported by tycho since we do
not witness the contract creation of rate providers and thus can't provide the required
contract state.
This is planned to be resolved with the dynamic contract indexing module.
## Static Attributes
| name | type | description |
|--------------------|-------|---------------------------------------------------------------------------------------------------------|
| pool_type | str | A unique identifier per pool type. Set depending on the factory |
| normalized weights | json | The normalised weights of a weighted pool. |
| pool_id | bytes | The balancer pool id. |
| rate_providers | json | A list of rate provider addresses. |
| bpt | bytes | The balancer lp token, set if the pool support entering and exiting lp postions via the swap interface. |
| main_token | bytes | The main token address for a linear pool |
| wrapped_token | bytes | The wrapped token address for a linear pool |
| fee | int | The fee charged by the pool set at deployment time |
| upper_target | int | The upper target for a linear pool |

View File

@@ -1,12 +1,11 @@
#![allow(clippy::all)]
pub mod composable_stable_pool_factory;
pub mod erc_linear_pool_factory;
pub mod euler_linear_pool_factory;
pub mod gearbox_linear_pool_factory;
pub mod managed_pool_factory;
pub mod silo_linear_pool_factory;
pub mod vault;
pub mod weighted_pool_factory;
pub mod weighted_pool_tokens_factory;
pub mod yearn_linear_pool_factory;
pub mod composable_stable_pool_factory;
pub mod vault;
pub mod weighted_pool_tokens_factory;
pub mod silo_linear_pool_factory;
pub mod euler_linear_pool_factory;
pub mod weighted_pool_factory;
pub mod managed_pool_factory;
pub mod erc_linear_pool_factory;
pub mod gearbox_linear_pool_factory;

View File

@@ -153,10 +153,7 @@ pub fn map_protocol_changes(
let default_attributes = vec![
Attribute {
name: "balance_owner".to_string(),
value: "0xBA12222222228d8Ba445958a75a0704d566BF2C8"
.to_string()
.as_bytes()
.to_vec(),
value: VAULT_ADDRESS.to_vec(),
change: ChangeType::Creation.into(),
},
Attribute {

View File

@@ -71,8 +71,17 @@ pub fn address_map(
&json_serialize_bigint_list(&create_call.normalized_weights),
),
(
"pool_id",
format!("0x{}", hex::encode(pool_registered.pool_id)).as_bytes(),
"pool_id", &pool_registered.pool_id,
),
(
"rate_providers",
&json_serialize_address_list(&create_call.rate_providers),
),
(
"fee",
&create_call
.swap_fee_percentage
.to_signed_bytes_be(),
),
("manual_updates", &[1u8]),
])
@@ -94,15 +103,20 @@ pub fn address_map(
.with_attributes(&[
("pool_type", "ComposableStablePoolFactory".as_bytes()),
(
"pool_id",
format!("0x{}", hex::encode(pool_registered.pool_id)).as_bytes(),
"pool_id", &pool_registered.pool_id,
),
("bpt", &pool_created.pool),
("manual_updates", &[1u8]),
(
"fee",
&create_call
.swap_fee_percentage
.to_signed_bytes_be(),
),
(
"rate_providers",
&json_serialize_address_list(&create_call.rate_providers),
),
("manual_updates", &[1u8]),
])
.as_swap_type("balancer_pool", ImplementationType::Vm),
)
@@ -128,8 +142,7 @@ pub fn address_map(
.to_signed_bytes_be(),
),
(
"pool_id",
format!("0x{}", hex::encode(pool_registered.pool_id)).as_bytes(),
"pool_id", &pool_registered.pool_id,
),
("manual_updates", &[1u8]),
("bpt", &pool_created.pool),
@@ -166,8 +179,7 @@ pub fn address_map(
.to_signed_bytes_be(),
),
(
"pool_id",
format!("0x{}", hex::encode(pool_registered.pool_id)).as_bytes(),
"pool_id", &pool_registered.pool_id,
),
("manual_updates", &[1u8]),
("bpt", &pool_created.pool),
@@ -252,8 +264,7 @@ pub fn address_map(
.to_signed_bytes_be(),
),
(
"pool_id",
format!("0x{}", hex::encode(pool_registered.pool_id)).as_bytes(),
"pool_id", &pool_registered.pool_id,
),
("manual_updates", &[1u8]),
("bpt", &pool_created.pool),
@@ -290,8 +301,7 @@ pub fn address_map(
.to_signed_bytes_be(),
),
(
"pool_id",
format!("0x{}", hex::encode(pool_registered.pool_id)).as_bytes(),
"pool_id", &pool_registered.pool_id,
),
("manual_updates", &[1u8]),
("bpt", &pool_created.pool),
@@ -324,8 +334,13 @@ pub fn address_map(
("pool_type", "WeightedPool2TokensFactory".as_bytes()),
("weights", &json_serialize_bigint_list(&create_call.weights)),
(
"pool_id",
format!("0x{}", hex::encode(pool_registered.pool_id)).as_bytes(),
"pool_id", &pool_registered.pool_id,
),
(
"fee",
&create_call
.swap_fee_percentage
.to_signed_bytes_be(),
),
("manual_updates", &[1u8]),
])

View File

@@ -5,119 +5,121 @@ adapter_contract: "BalancerV2SwapAdapter"
skip_balance_check: true
initialized_accounts:
- "0xba12222222228d8ba445958a75a0704d566bf2c8"
# Uncomment entries below to include composable stable pool dependencies
# wstETH dependencies
# - "0x72D07D7DcA67b8A406aD1Ec34ce969c90bFEE768"
# - "0xb8ffc3cd6e7cf5a098a1c92f48009765b24088dc"
# - "0xae7ab96520de3a18e5e111b5eaab095312d7fe84"
# - "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0"
# - "0x2b33cf282f867a7ff693a66e11b0fcc5552e4425"
# - "0x17144556fd3424edc8fc8a4c940b2d04936d17eb"
# sfrxETH dependencies
# - "0x302013E7936a39c358d07A3Df55dc94EC417E3a1"
# - "0xac3e018457b222d93114458476f3e3416abbe38f"
# rETH dependencies
# - "0x1a8F81c256aee9C640e14bB0453ce247ea0DFE6F"
# - "0x07fcabcbe4ff0d80c2b1eb42855c0131b6cba2f4"
# - "0x1d8f8f00cfa6758d7be78336684788fb0ee0fa46"
# - "0xae78736cd615f374d3085123a210448e74fc6393"
tests:
# WeightedPoolFactory - 0x897888115Ada5773E02aA29F775430BFB5F34c51
- name: test_weighted_pool_creation
start_block: 16971010
stop_block: 16972246
start_block: 20128706
stop_block: 20128806
expected_state:
protocol_components:
- id: "0xDac7eF49161bdBf0e8f0B4c8e2D38DF19D972874"
- id: "0xe96a45f66bdDA121B24F0a861372A72E8889523d"
tokens:
- "0x9A62fB1CAFEa99f8f0441f80af7F7ccf0d46847D"
- "0x38C2a4a7330b22788374B8Ff70BBa513C8D848cA"
- "0x514910771AF9Ca656af840dff83E8264EcF986CA"
static_attributes: null
creation_tx: "0xa63c671046ad2075ec8ea83ac21199cf3e3a5f433e72ec4c117cbabfb9b18de2"
# WeightedPool2TokensFactory - 0xA5bf2ddF098bb0Ef6d120C98217dD6B141c74EE0
- name: weighted_legacy_creation
start_block: 13148365
stop_block: 13148465
expected_state:
protocol_components:
- id: "0xBF96189Eee9357a95C7719f4F5047F76bdE804E5"
tokens:
- "0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
static_attributes:
creation_tx: "0xbed0c745c3761cd54a7489181a5f1165c628c35ef69ecb0bfeec08f09f0ec407"
static_attributes: null
creation_tx: "0xdced662e41b1608c386551bbc89894a10321fd8bd58782e22077d1044cf99cb5"
# ComposableStablePoolFactory - 0xDB8d758BCb971e482B2C45f7F8a7740283A1bd3A
- name: test_composable_stable_pool_creation
start_block: 17672478
stop_block: 17677310
start_block: 17677300
stop_block: 17678400
expected_state:
protocol_components:
- id: "0x20356663C17D31549d1210379749E2aE36722D8f"
tokens:
- "0xba100000625a3754423978a60c9317c58a424e3D"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
static_attributes:
creation_tx: "0x822653ae905ab40f51f46c7b8185ba9a4aa06e674789f87dd26d0d11b26dc7c9"
- id: "0x42ED016F826165C2e5976fe5bC3df540C5aD0Af7"
tokens:
- "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
- "0xac3E018457B222d93114458476f3E3416Abbe38F"
- "0xae78736Cd615f374D3085123A210448E74Fc6393"
static_attributes:
creation_tx: "0x53ff6bab0d8a76a998e29e59da8068ad906ae85507a1c2fbf2505e2cb52fd754"
protocol_components:
- id: "0x42ED016F826165C2e5976fe5bC3df540C5aD0Af7"
tokens:
- "0x42ed016f826165c2e5976fe5bc3df540c5ad0af7"
- "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0"
- "0xac3E018457B222d93114458476f3E3416Abbe38F"
- "0xae78736Cd615f374D3085123A210448E74Fc6393"
static_attributes: null
skip_simulation: true
creation_tx: "0x53ff6bab0d8a76a998e29e59da8068ad906ae85507a1c2fbf2505e2cb52fd754"
# ERC4626LinearPoolFactory - 0x813EE7a840CE909E7Fea2117A44a90b8063bd4fd
- name: test_erc4626_linear_pool_creation
start_block: 17045881
stop_block: 17480143
start_block: 17480142
stop_block: 17480242
expected_state:
protocol_components:
- id: "0x9516a2d25958EdB8da246a320f2c7d94A0DBe25d"
tokens:
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
- "0xB99eDc4b289B0F2284fCF3f66884191BdCe29624"
static_attributes:
creation_tx: "0x756e81cea4cf725c738bcef3852ad57687156b561574cad3e2956e6cb48da5e6"
- id: "0x3fCb7085B8F2F473F80bF6D879cAe99eA4DE9344"
tokens:
- "0x39Dd7790e75C6F663731f7E1FdC0f35007D3879b"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
static_attributes:
creation_tx: "0x5ff97870685370bab3876a4335d28c42e24659064fe78b486d6fb1b37b992877"
protocol_components:
- id: "0x3fCb7085B8F2F473F80bF6D879cAe99eA4DE9344"
tokens:
- "0x39Dd7790e75C6F663731f7E1FdC0f35007D3879b"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
- "0x3fcb7085b8f2f473f80bf6d879cae99ea4de9344"
static_attributes: null
skip_simulation: true
creation_tx: "0x5ff97870685370bab3876a4335d28c42e24659064fe78b486d6fb1b37b992877"
# EulerLinearPoolFactory - 0x5F43FBa61f63Fa6bFF101a0A0458cEA917f6B347
- name: test_euler_linear_pool_creation
start_block: 16588078
stop_block: 16588118
start_block: 16588117
stop_block: 16588217
expected_state:
protocol_components:
- id: "0xDEC02e6642e2c999aF429F5cE944653CAd15e093"
tokens:
- "0xC101dcA301a4011C1F925e9622e749e550a1B667"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
static_attributes:
creation_tx: "0xd639c8a6c3a553d47fd7f3d384ec4bc50a2cd6dfb2c3135b7f5db49d73c15df2"
- id: "0xD4e7C1F3DA1144c9E2CfD1b015eDA7652b4a4399"
tokens:
- "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- "0xEb91861f8A4e1C12333F42DCE8fB0Ecdc28dA716"
static_attributes:
creation_tx: "0x4a9ea683052afefdae3d189862868c3a7dc8f431d1d9828b6bfd9451a8816426"
protocol_components:
- id: "0xD4e7C1F3DA1144c9E2CfD1b015eDA7652b4a4399"
tokens:
- "0xD4e7C1F3DA1144c9E2CfD1b015eDA7652b4a4399"
- "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- "0xEb91861f8A4e1C12333F42DCE8fB0Ecdc28dA716"
static_attributes: null
skip_simulation: true
creation_tx: "0x4a9ea683052afefdae3d189862868c3a7dc8f431d1d9828b6bfd9451a8816426"
# SiloLinearPoolFactory - 0x4E11AEec21baF1660b1a46472963cB3DA7811C89
- name: test_silo_linear_pool_creation
start_block: 17173185
stop_block: 17173187
expected_state:
protocol_components:
- id: "0x74CBfAF94A3577c539a9dCEE9870A6349a33b34f"
tokens:
- "0x192E67544694a7bAA2DeA94f9B1Df58BB3395A12"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
static_attributes:
creation_tx: "0xd639c8a6c3a553d47fd7f3d384ec4bc50a2cd6dfb2c3135b7f5db49d73c15df2"
protocol_components:
- id: "0x74CBfAF94A3577c539a9dCEE9870A6349a33b34f"
tokens:
- "0x192E67544694a7bAA2DeA94f9B1Df58BB3395A12"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
- "0x74cbfaf94a3577c539a9dcee9870a6349a33b34f"
static_attributes: null
skip_simulation: true
creation_tx: "0x215c9f4256ab450368132f4063611ae8cdd98e80bea7e44ecf0600ed1d757018"
# YearnLinearPoolFactory - 0x5F5222Ffa40F2AEd6380D022184D6ea67C776eE0a
- name: test_yearn_linear_pool_creation
start_block: 17052601
stop_block: 17052605
expected_state:
protocol_components:
- id: "0x5F5222Ffa40F2AEd6380D022184D6ea67C776eE0"
tokens:
- "0x806E02Dea8d4a0882caD9fA3Fa75B212328692dE"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
static_attributes:
creation_tx: "0x497aa03ce84d236c183204ddfc6762c8e4158da1ebc5e7e18e7f6cceaa497a2a"
# WeightedPool2TokensFactory - 0xA5bf2ddF098bb0Ef6d120C98217dD6B141c74EE0
- name: weighted_legacy_creation
start_block: 12349890
stop_block: 12364015
expected_state: { }
protocol_components:
- id: "0x021c343C6180f03cE9E48FaE3ff432309b9aF199"
tokens:
- "0xD291E7a03283640FDc51b121aC401383A46cC623"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
static_attributes:
creation_tx: "0xc6b9f8ee6c6f17edacc6df1b6287c57157a16f2aa5b315a03cf2c42d7ebb74e3"
- id: "0x571046EaE58C783f29f95ADBa17Dd561Af8a8712"
tokens:
- "0x6B175474E89094C44Da98b954EedeAC495271d0F"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
static_attributes:
creation_tx: "0xe60d97670f902d58e65fb2d56f77a0cee19ffad47deae1fb8a126d534ee1ece5"
protocol_components:
- id: "0xac5b4ef7ede2f2843a704e96dcaa637f4ba3dc3f"
tokens:
- "0x806E02Dea8d4a0882caD9fA3Fa75B212328692dE"
- "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
- "0xac5b4ef7ede2f2843a704e96dcaa637f4ba3dc3f"
static_attributes: null
skip_simulation: true
creation_tx: "0x497aa03ce84d236c183204ddfc6762c8e4158da1ebc5e7e18e7f6cceaa497a2a"

View File

@@ -85,7 +85,6 @@ class TestRunner:
else:
print(f"❗️ {test['name']} failed: {result.message}")
def validate_state(self, expected_state: dict, stop_block: int) -> TestResult:
"""Validate the current protocol state against the expected state."""
protocol_components = self.tycho_rpc_client.get_protocol_components()
@@ -153,7 +152,8 @@ class TestRunner:
contract_states = self.tycho_rpc_client.get_contract_state()
filtered_components = {'protocol_components': [pc for pc in protocol_components["protocol_components"] if
pc["id"] in [c["id"].lower() for c in
expected_state["protocol_components"] if c["skip_simulation"] is False]]}
expected_state["protocol_components"] if
c.get("skip_simulation", False) is False]]}
simulation_failures = self.simulate_get_amount_out(
stop_block,
protocol_states,
@@ -198,7 +198,7 @@ class TestRunner:
self.adapters_src, "out", f"{self.config['adapter_contract']}.sol",
f"{self.config['adapter_contract']}.evm.runtime"
)
decoder = ThirdPartyPoolTychoDecoder(adapter_contract, 0, False)
decoder = ThirdPartyPoolTychoDecoder(adapter_contract, 0)
stream_adapter = TychoPoolStateStreamAdapter(
tycho_url="0.0.0.0:4242",
protocol=protocol,

View File

@@ -20,10 +20,9 @@ log = getLogger(__name__)
class ThirdPartyPoolTychoDecoder:
"""ThirdPartyPool decoder for protocol messages from the Tycho feed"""
def __init__(self, adapter_contract: str, minimum_gas: int, hard_limit: bool):
def __init__(self, adapter_contract: str, minimum_gas: int):
self.adapter_contract = adapter_contract
self.minimum_gas = minimum_gas
self.hard_limit = hard_limit
def decode_snapshot(
self,
@@ -68,8 +67,7 @@ class ThirdPartyPoolTychoDecoder:
exchange=exchange,
adapter_contract_name=self.adapter_contract,
minimum_gas=self.minimum_gas,
hard_sell_limit=self.hard_limit,
trace=True,
trace=False,
**optional_attributes,
)
@@ -77,15 +75,16 @@ class ThirdPartyPoolTychoDecoder:
def decode_optional_attributes(component, snap, block_number):
# Handle optional state attributes
attributes = snap["state"]["attributes"]
pool_id = attributes.get("pool_id") or component["id"]
balance_owner = attributes.get("balance_owner")
stateless_contracts = {}
static_attributes = snap["component"]["static_attributes"]
pool_id = static_attributes.get("pool_id") or component["id"]
index = 0
while f"stateless_contract_addr_{index}" in static_attributes:
encoded_address = static_attributes[f"stateless_contract_addr_{index}"]
decoded = bytes.fromhex(encoded_address[2:] if encoded_address.startswith('0x') else encoded_address).decode('utf-8')
decoded = bytes.fromhex(
encoded_address[2:] if encoded_address.startswith('0x') else encoded_address).decode('utf-8')
if decoded.startswith("call"):
address = ThirdPartyPoolTychoDecoder.get_address_from_call(block_number, decoded)
else:
@@ -94,13 +93,13 @@ class ThirdPartyPoolTychoDecoder:
code = static_attributes.get(f"stateless_contract_code_{index}") or get_code_for_address(address)
stateless_contracts[address] = code
index += 1
index = 0
while f"stateless_contract_addr_{index}" in attributes:
address = attributes[f"stateless_contract_addr_{index}"]
code = attributes.get(f"stateless_contract_code_{index}") or get_code_for_address(address)
stateless_contracts[address] = code
index += 1
index += 1
return {
"balance_owner": balance_owner,
"pool_id": pool_id,

View File

@@ -26,10 +26,10 @@ log = getLogger(__name__)
class TokenLoader:
def __init__(
self,
tycho_url: str,
blockchain: Blockchain,
min_token_quality: Optional[int] = 0,
self,
tycho_url: str,
blockchain: Blockchain,
min_token_quality: Optional[int] = 0,
):
self.tycho_url = tycho_url
self.blockchain = blockchain
@@ -45,10 +45,10 @@ class TokenLoader:
start = time.monotonic()
all_tokens = []
while data := self._get_all_with_pagination(
url=url,
page=page,
limit=self._token_limit,
params={"min_quality": self.min_token_quality},
url=url,
page=page,
limit=self._token_limit,
params={"min_quality": self.min_token_quality},
):
all_tokens.extend(data)
page += 1
@@ -73,10 +73,10 @@ class TokenLoader:
start = time.monotonic()
all_tokens = []
while data := self._get_all_with_pagination(
url=url,
page=page,
limit=self._token_limit,
params={"min_quality": self.min_token_quality, "addresses": addresses},
url=url,
page=page,
limit=self._token_limit,
params={"min_quality": self.min_token_quality, "addresses": addresses},
):
all_tokens.extend(data)
page += 1
@@ -95,7 +95,7 @@ class TokenLoader:
@staticmethod
def _get_all_with_pagination(
url: str, params: Optional[Dict] = None, page: int = 0, limit: int = 50
url: str, params: Optional[Dict] = None, page: int = 0, limit: int = 50
) -> Dict:
if params is None:
params = {}
@@ -122,14 +122,14 @@ class BlockProtocolChanges:
class TychoPoolStateStreamAdapter:
def __init__(
self,
tycho_url: str,
protocol: str,
decoder: ThirdPartyPoolTychoDecoder,
blockchain: Blockchain,
min_tvl: Optional[Decimal] = 10,
min_token_quality: Optional[int] = 0,
include_state=True,
self,
tycho_url: str,
protocol: str,
decoder: ThirdPartyPoolTychoDecoder,
blockchain: Blockchain,
min_tvl: Optional[Decimal] = 10,
min_token_quality: Optional[int] = 0,
include_state=True,
):
"""
:param tycho_url: URL to connect to Tycho DB
@@ -238,7 +238,7 @@ class TychoPoolStateStreamAdapter:
@staticmethod
def build_snapshot_message(
protocol_components: dict, protocol_states: dict, contract_states: dict
protocol_components: dict, protocol_states: dict, contract_states: dict
) -> dict[str, ThirdPartyPool]:
vm_states = {state["address"]: state for state in contract_states["accounts"]}
states = {}
@@ -248,7 +248,7 @@ class TychoPoolStateStreamAdapter:
for state in protocol_states["states"]:
pool_id = state["component_id"]
if pool_id not in states:
log.warning(f"State for pool {pool_id} not found in components")
log.debug(f"{pool_id} was present in snapshot but not in components")
continue
states[pool_id]["state"] = state
snapshot = {"vm_storage": vm_states, "states": states}
@@ -269,7 +269,7 @@ class TychoPoolStateStreamAdapter:
return self.process_snapshot(block, state_msg["snapshot"])
def process_snapshot(
self, block: EVMBlock, state_msg: dict
self, block: EVMBlock, state_msg: dict
) -> BlockProtocolChanges:
start = time.monotonic()
removed_pools = set()