Skip to content

Commit

Permalink
Use new quote API for cowswap oracle
Browse files Browse the repository at this point in the history
- markets API was deprecated
  • Loading branch information
Uxio0 committed Jan 19, 2023
1 parent 13a4365 commit 1f64745
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 16 deletions.
8 changes: 6 additions & 2 deletions gnosis/eth/oracles/cowswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ def get_price(
result = self.api.get_estimated_amount(
token_address_1, token_address_2, OrderKind.SELL, 10**token_1_decimals
)
if "amount" in result:
if "buyAmount" in result:
# Decimals needs to be adjusted
token_2_decimals = get_decimals(token_address_2, self.ethereum_client)
return float(result["amount"]) / 10**token_2_decimals
return (
float(result["buyAmount"])
/ result["sellAmount"]
* 10 ** (token_1_decimals - token_2_decimals)
)

exception = None
except IOError as exc:
Expand Down
4 changes: 3 additions & 1 deletion gnosis/eth/tests/oracles/test_cowswap.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ def test_get_price(self):
)
self.assertAlmostEqual(price, 1.0, delta=0.5)

with mock.patch.object(Session, "get", side_effect=IOError("Connection Error")):
with mock.patch.object(
Session, "post", side_effect=IOError("Connection Error")
):
with self.assertRaisesMessage(
CannotGetPriceFromOracle,
f"Cannot get price from CowSwap "
Expand Down
59 changes: 47 additions & 12 deletions gnosis/protocol/gnosis_protocol_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from gnosis.eth import EthereumNetwork, EthereumNetworkNotSupported
from gnosis.eth.eip712 import eip712_encode_hash

from ..eth.constants import NULL_ADDRESS
from .order import Order, OrderKind


Expand All @@ -27,8 +28,8 @@ class TradeResponse(TypedDict):


class AmountResponse(TypedDict):
amount: str
token: AnyAddress
sellAmount: int
buyAmount: int


class ErrorResponse(TypedDict):
Expand Down Expand Up @@ -77,13 +78,15 @@ def weth_address(self) -> ChecksumAddress:
else: # XDAI
return ChecksumAddress("0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1")

def get_fee(self, order: Order, from_address: ChecksumAddress) -> int:
def get_quote(
self, order: Order, from_address: ChecksumAddress
) -> Union[Dict[str, Any], ErrorResponse]:
url = self.base_url + "quote"
data_json = {
"sellToken": order.sellToken.lower(),
"buyToken": order.buyToken.lower(),
"sellAmountBeforeFee": str(order.sellAmount),
"validTo": order.validTo,
# "validTo": order.validTo,
"appData": HexBytes(order.appData).hex()
if isinstance(order.appData, bytes)
else order.appData,
Expand All @@ -96,10 +99,20 @@ def get_fee(self, order: Order, from_address: ChecksumAddress) -> int:
}
r = self.http_session.post(url, json=data_json)
if r.ok:
return int(r.json()["quote"]["feeAmount"])
return r.json()
else:
return ErrorResponse(r.json())

def get_fee(
self, order: Order, from_address: ChecksumAddress
) -> Union[int, ErrorResponse]:
quote = self.get_quote(order, from_address)

if "quote" in quote:
return int(quote["quote"]["feeAmount"])
else:
return quote

def place_order(
self, order: Order, private_key: HexStr
) -> Union[HexStr, ErrorResponse]:
Expand Down Expand Up @@ -193,14 +206,36 @@ def get_estimated_amount(
base_token: ChecksumAddress,
quote_token: ChecksumAddress,
kind: OrderKind,
amount: int,
amount_wei: int,
) -> Union[AmountResponse, ErrorResponse]:
"""
The estimated amount in quote token for either buying or selling amount of baseToken.
:param base_token:
:param quote_token:
:param kind:
:param amount_wei:
:return: Both `sellAmount` and `buyAmount` as they can be adjusted by CowSwap API
"""
url = self.base_url + f"markets/{base_token}-{quote_token}/{kind.name}/{amount}"
r = self.http_session.get(url)
if r.ok:
return AmountResponse(r.json())
order = Order(
sellToken=base_token,
buyToken=quote_token,
receiver=NULL_ADDRESS,
sellAmount=amount_wei * 10,
buyAmount=0,
validTo=0, # Valid for 1 hour
appData="0x0000000000000000000000000000000000000000000000000000000000000000",
feeAmount=0,
kind=kind.name.lower(), # `sell` or `buy`
partiallyFillable=False,
sellTokenBalance="erc20", # `erc20`, `external` or `internal`
buyTokenBalance="erc20", # `erc20` or `internal`
)

quote = self.get_quote(order, NULL_ADDRESS)
if "quote" in quote:
return {
"buyAmount": int(quote["quote"]["buyAmount"]),
"sellAmount": int(quote["quote"]["sellAmount"]),
}
else:
return ErrorResponse(r.json())
return quote
2 changes: 1 addition & 1 deletion gnosis/protocol/tests/test_gnosis_protocol_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def test_get_estimated_amount(self):
OrderKind.SELL,
int(1e18),
)
amount = int(response["amount"]) / 1e18
amount = float(response["buyAmount"]) / response["sellAmount"]
self.assertGreater(amount, 0)
self.assertLess(amount, 1)

Expand Down

0 comments on commit 1f64745

Please sign in to comment.