Skip to content

Commit

Permalink
add aggregation methods; finish deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
bout3fiddy committed Jul 13, 2024
1 parent a4abd64 commit 73c997a
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 44 deletions.
111 changes: 74 additions & 37 deletions contracts/RateProvider.vy
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

version: public(constant(String[8])) = "1.0.0"

from vyper.interfaces import ERC20Detailed

MAX_COINS: constant(uint256) = 8
MAX_QUOTES: constant(uint256) = 100

Expand Down Expand Up @@ -38,18 +40,67 @@ interface Metaregistry:
ADDRESS_PROVIDER: public(immutable(AddressProvider))
METAREGISTRY_ID: constant(uint256) = 7
STABLESWAP_META_ABI: constant(String[64]) = "get_dy_underlying(int128,int128,uint256)"
STABLESWA_ABI: constant(String[64]) = "get_dy(int128,int128,uint256)"
STABLESWAP_ABI: constant(String[64]) = "get_dy(int128,int128,uint256)"
CRYPTOSWAP_ABI: constant(String[64]) = "get_dy(uint256,uint256,uint256)"

@external
def __init__(address_provider: address):
ADDRESS_PROVIDER = AddressProvider(address_provider)

# Quote View method

@external
@view
def get_quotes(source_token: address, destination_token: address, amount_in: uint256) -> DynArray[Quote, MAX_QUOTES]:
return self._get_quotes(source_token, destination_token, amount_in)


@external
@view
def get_aggregated_rate(source_token: address, destination_token: address) -> uint256:

amount_in: uint256 = 10**convert(ERC20Detailed(source_token).decimals(), uint256)
quotes: DynArray[Quote, MAX_QUOTES] = self._get_quotes(source_token, destination_token, amount_in)

return self.weighted_average_quote(
convert(ERC20Detailed(source_token).decimals(), uint256),
convert(ERC20Detailed(destination_token).decimals(), uint256),
quotes,
)


@internal
@pure
def weighted_average_quote(
source_token_decimals: uint256,
dest_token_decimals: uint256,
quotes: DynArray[Quote, MAX_QUOTES]
) -> uint256:

num_quotes: uint256 = len(quotes)

# Calculate total balance with normalization
total_balance: uint256 = 0
for i in range(num_quotes, bound=MAX_QUOTES):
source_balance_normalized: uint256 = quotes[i].source_token_pool_balance * 10**(18 - source_token_decimals)
dest_balance_normalized: uint256 = quotes[i].dest_token_pool_balance * 10**(18 - dest_token_decimals)
total_balance += source_balance_normalized + dest_balance_normalized


# Calculate weighted sum with normalization
weighted_avg: uint256 = 0
for i in range(num_quotes, bound=MAX_QUOTES):
source_balance_normalized: uint256 = quotes[i].source_token_pool_balance * 10**(18 - source_token_decimals)
dest_balance_normalized: uint256 = quotes[i].dest_token_pool_balance * 10**(18 - dest_token_decimals)
pool_balance_normalized: uint256 = source_balance_normalized + dest_balance_normalized
weight: uint256 = (pool_balance_normalized * 10**18) / total_balance # Use 18 decimal places for precision
weighted_avg += weight * quotes[i].amount_out / 10**18

return weighted_avg


@internal
@view
def _get_quotes(source_token: address, destination_token: address, amount_in: uint256) -> DynArray[Quote, MAX_QUOTES]:

quotes: DynArray[Quote, MAX_QUOTES] = []
metaregistry: Metaregistry = Metaregistry(ADDRESS_PROVIDER.get_address(METAREGISTRY_ID))
Expand All @@ -72,16 +123,20 @@ def get_quotes(source_token: address, destination_token: address, amount_in: uin

# get balances
balances: uint256[MAX_COINS] = metaregistry.get_underlying_balances(pool)
dyn_balances: DynArray[uint256, MAX_COINS] = []
for bal in balances:
if bal > 0:
dyn_balances.append(bal)

# if pool is too small, dont post call and skip pool:
if 0 in balances or balances[i] <= amount_in:
# skip if pool is too small
if 0 in dyn_balances:
continue

# do a get_dy call and only save quote if call does not bork; use correct abi (in128 vs uint256)
quote: uint256 = self._get_pool_quote(i, j, amount_in, pool, pool_type, is_underlying)

# check if get_dy works and if so, append quote to dynarray
if quote > 0:
if quote > 0 and len(quotes) < MAX_QUOTES:
quotes.append(
Quote(
{
Expand All @@ -103,6 +158,7 @@ def get_quotes(source_token: address, destination_token: address, amount_in: uin
@internal
@view
def _get_pool_type(pool: address, metaregistry: Metaregistry) -> uint8:

# 0 for stableswap, 1 for cryptoswap, 2 for LLAMMA.

success: bool = False
Expand Down Expand Up @@ -137,49 +193,29 @@ def _get_pool_type(pool: address, metaregistry: Metaregistry) -> uint8:
@view
def _get_pool_quote(
i: int128,
j: int128,
amount_in: uint256,
pool: address,
pool_type: uint8,
j: int128,
amount_in: uint256,
pool: address,
pool_type: uint8,
is_underlying: bool
) -> uint256:

success: bool = False
response: Bytes[32] = b""
if pool_type == 0 and is_underlying:
method_abi: Bytes[4] = b""

success, response = raw_call(
pool,
concat(
method_id(STABLESWAP_META_ABI),
convert(i, bytes32),
convert(j, bytes32),
convert(amount_in, bytes32),
),
max_outsize=32,
revert_on_failure=False,
is_static_call=True
)
# choose the right abi:
if pool_type == 0 and is_underlying:
method_abi = method_id(STABLESWAP_META_ABI)
elif pool_type == 0 and not is_underlying:

success, response = raw_call(
pool,
concat(
method_id(STABLESWA_ABI),
convert(i, bytes32),
convert(j, bytes32),
convert(amount_in, bytes32),
),
max_outsize=32,
revert_on_failure=False,
is_static_call=True
)
method_abi = method_id(STABLESWAP_ABI)
else:
method_abi = method_id(CRYPTOSWAP_ABI)

success, response = raw_call(
success, response = raw_call(
pool,
concat(
method_id(CRYPTOSWAP_ABI),
method_abi,
convert(i, bytes32),
convert(j, bytes32),
convert(amount_in, bytes32),
Expand All @@ -188,6 +224,7 @@ def _get_pool_quote(
revert_on_failure=False,
is_static_call=True
)

if success:
return convert(response, uint256)

Expand Down
21 changes: 14 additions & 7 deletions scripts/deploy_rate_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import sys

import boa
import yaml
from boa.network import NetworkEnv
from eth.constants import ZERO_ADDRESS
from eth_account import Account
from rich import console as rich_console

Expand Down Expand Up @@ -47,30 +45,39 @@ def main(network, fork, url):
address_provider = boa.load_partial("contracts/AddressProviderNG.vy").at(
ADDRESS_PROVIDER
)

console.log("Deploying rate provider ...")
rate_provider = boa.load(
"contracts/RateProvider.vy", address_provider.address
)

console.log("Adding rate provider to address provider")
address_provider.add_new_id(
18, rate_provider.address, "Spot Rate Provider"
)
if address_provider.get_address(18) == ZERO_ADDRESS:
address_provider.add_new_id(
18, rate_provider.address, "Spot Rate Provider"
)
elif address_provider.get_address(18) != rate_provider.address:
address_provider.update_address(18, rate_provider.address)


if __name__ == "__main__":
network = "arbitrum"
network = "zksync"
url = ""
fork = False

if network == "zksync":
import boa_zksync

url = "https://mainnet.era.zksync.io"
network_url = "https://mainnet.era.zksync.io"
ADDRESS_PROVIDER = "0x54A5a69e17Aa6eB89d77aa3828E38C9Eb4fF263D"
elif network == "fraxtal":
network_url = "https://rpc.frax.com"
elif network == "kava":
network_url = "https://rpc.ankr.com/kava_evm"
elif network == "xlayer":
network_url = "https://xlayerrpc.okx.com"
elif network == "mantle":
network_url = "https://rpc.mantle.xyz"
else:
network_url = fetch_url(network)

Expand Down

0 comments on commit 73c997a

Please sign in to comment.