From 21deda790cd8d4b0e85198a6e156b826082919fd Mon Sep 17 00:00:00 2001 From: Mikhail Mikheev Date: Mon, 11 Oct 2021 17:58:48 +0200 Subject: [PATCH] Feature: Oracle for cream.finance tokens (#100) * Add oracle for cream.finance tokens * Set version 3.4.5 --- gnosis/eth/oracles/__init__.py | 12 +- gnosis/eth/oracles/abis/cream_abis.py | 922 ++++++++++++++++++++++++++ gnosis/eth/oracles/oracles.py | 26 +- gnosis/eth/tests/test_oracles.py | 33 +- setup.py | 2 +- 5 files changed, 982 insertions(+), 13 deletions(-) create mode 100644 gnosis/eth/oracles/abis/cream_abis.py diff --git a/gnosis/eth/oracles/__init__.py b/gnosis/eth/oracles/__init__.py index d43d0a303..28a61721f 100644 --- a/gnosis/eth/oracles/__init__.py +++ b/gnosis/eth/oracles/__init__.py @@ -1,8 +1,8 @@ # flake8: noqa F401 from .oracles import (AaveOracle, BalancerOracle, CannotGetPriceFromOracle, - ComposedPriceOracle, CurveOracle, EnzymeOracle, - InvalidPriceFromOracle, KyberOracle, MooniswapOracle, - OracleException, PoolTogetherOracle, PriceOracle, - PricePoolOracle, SushiswapOracle, UnderlyingToken, - UniswapOracle, UniswapV2Oracle, UsdPricePoolOracle, - YearnOracle) + ComposedPriceOracle, CreamOracle, CurveOracle, + EnzymeOracle, InvalidPriceFromOracle, KyberOracle, + MooniswapOracle, OracleException, PoolTogetherOracle, + PriceOracle, PricePoolOracle, SushiswapOracle, + UnderlyingToken, UniswapOracle, UniswapV2Oracle, + UsdPricePoolOracle, YearnOracle, ZerionComposedOracle) diff --git a/gnosis/eth/oracles/abis/cream_abis.py b/gnosis/eth/oracles/abis/cream_abis.py new file mode 100644 index 000000000..812159621 --- /dev/null +++ b/gnosis/eth/oracles/abis/cream_abis.py @@ -0,0 +1,922 @@ +cream_ctoken_abi = [ + { + 'inputs': [ + {'internalType': 'address', 'name': 'underlying_', + 'type': 'address'}, + {'internalType': 'contract ComptrollerInterface', + 'name': 'comptroller_', 'type': 'address'}, + {'internalType': 'contract InterestRateModel', + 'name': 'interestRateModel_', 'type': 'address'}, + {'internalType': 'uint256', + 'name': 'initialExchangeRateMantissa_', 'type': 'uint256' + }, + {'internalType': 'string', 'name': 'name_', 'type': 'string' + }, + {'internalType': 'string', 'name': 'symbol_', + 'type': 'string'}, + {'internalType': 'uint8', 'name': 'decimals_', + 'type': 'uint8'}, + {'internalType': 'address payable', 'name': 'admin_', + 'type': 'address'}, + {'internalType': 'address', 'name': 'implementation_', + 'type': 'address'}, + {'internalType': 'bytes', 'name': 'becomeImplementationData', 'type': 'bytes'}, + ], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'constructor', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'uint256', + 'name': 'cashPrior', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'interestAccumulated', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'borrowIndex', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'totalBorrows', + 'type': 'uint256', + }], + 'name': 'AccrueInterest', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': True, + 'internalType': 'address', + 'name': 'owner', + 'type': 'address', + }, { + 'indexed': True, + 'internalType': 'address', + 'name': 'spender', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'amount', + 'type': 'uint256', + }], + 'name': 'Approval', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'borrower', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'borrowAmount', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'accountBorrows', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'totalBorrows', + 'type': 'uint256', + }], + 'name': 'Borrow', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'uint256', + 'name': 'error', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'info', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'detail', + 'type': 'uint256', + }], + 'name': 'Failure', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'liquidator', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'address', + 'name': 'borrower', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'repayAmount', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'address', + 'name': 'cTokenCollateral', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'seizeTokens', + 'type': 'uint256', + }], + 'name': 'LiquidateBorrow', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'minter', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'mintAmount', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'mintTokens', + 'type': 'uint256', + }], + 'name': 'Mint', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'oldAdmin', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'address', + 'name': 'newAdmin', + 'type': 'address', + }], + 'name': 'NewAdmin', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'contract ComptrollerInterface', + 'name': 'oldComptroller', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'contract ComptrollerInterface', + 'name': 'newComptroller', + 'type': 'address', + }], + 'name': 'NewComptroller', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'oldImplementation', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'address', + 'name': 'newImplementation', + 'type': 'address', + }], + 'name': 'NewImplementation', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'contract InterestRateModel', + 'name': 'oldInterestRateModel', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'contract InterestRateModel', + 'name': 'newInterestRateModel', + 'type': 'address', + }], + 'name': 'NewMarketInterestRateModel', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'oldPendingAdmin', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'address', + 'name': 'newPendingAdmin', + 'type': 'address', + }], + 'name': 'NewPendingAdmin', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'uint256', + 'name': 'oldReserveFactorMantissa', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'newReserveFactorMantissa', + 'type': 'uint256', + }], + 'name': 'NewReserveFactor', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'redeemer', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'redeemAmount', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'redeemTokens', + 'type': 'uint256', + }], + 'name': 'Redeem', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'payer', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'address', + 'name': 'borrower', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'repayAmount', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'accountBorrows', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'totalBorrows', + 'type': 'uint256', + }], + 'name': 'RepayBorrow', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'benefactor', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'addAmount', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'newTotalReserves', + 'type': 'uint256', + }], + 'name': 'ReservesAdded', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': False, + 'internalType': 'address', + 'name': 'admin', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'reduceAmount', + 'type': 'uint256', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'newTotalReserves', + 'type': 'uint256', + }], + 'name': 'ReservesReduced', + 'type': 'event', + }, + { + 'anonymous': False, + 'inputs': [{ + 'indexed': True, + 'internalType': 'address', + 'name': 'from', + 'type': 'address', + }, { + 'indexed': True, + 'internalType': 'address', + 'name': 'to', + 'type': 'address', + }, { + 'indexed': False, + 'internalType': 'uint256', + 'name': 'amount', + 'type': 'uint256', + }], + 'name': 'Transfer', + 'type': 'event', + }, + {'payable': True, 'stateMutability': 'payable', 'type': 'fallback' + }, + { + 'constant': False, + 'inputs': [], + 'name': '_acceptAdmin', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'uint256', 'name': 'addAmount', + 'type': 'uint256'}], + 'name': '_addReserves', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'uint256', 'name': 'reduceAmount', + 'type': 'uint256'}], + 'name': '_reduceReserves', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'contract ComptrollerInterface', + 'name': 'newComptroller', 'type': 'address'}], + 'name': '_setComptroller', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'address', 'name': 'implementation_', 'type': 'address'}, {'internalType': 'bool', + 'name': 'allowResign', 'type': 'bool'}, + {'internalType': 'bytes', + 'name': 'becomeImplementationData', 'type': 'bytes' + }], + 'name': '_setImplementation', + 'outputs': [], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'contract InterestRateModel', + 'name': 'newInterestRateModel', 'type': 'address'}], + 'name': '_setInterestRateModel', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'address payable', + 'name': 'newPendingAdmin', 'type': 'address'}], + 'name': '_setPendingAdmin', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'uint256', + 'name': 'newReserveFactorMantissa', 'type': 'uint256' + }], + 'name': '_setReserveFactor', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'accrualBlockNumber', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [], + 'name': 'accrueInterest', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'admin', + 'outputs': [{'internalType': 'address payable', 'name': '', + 'type': 'address'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [{'internalType': 'address', 'name': 'owner', + 'type': 'address'}, {'internalType': 'address', + 'name': 'spender', 'type': 'address'}], + 'name': 'allowance', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'address', 'name': 'spender', + 'type': 'address'}, {'internalType': 'uint256', + 'name': 'amount', 'type': 'uint256'}], + 'name': 'approve', + 'outputs': [{'internalType': 'bool', 'name': '', 'type': 'bool' + }], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [{'internalType': 'address', 'name': 'owner', + 'type': 'address'}], + 'name': 'balanceOf', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'address', 'name': 'owner', + 'type': 'address'}], + 'name': 'balanceOfUnderlying', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'uint256', 'name': 'borrowAmount', + 'type': 'uint256'}], + 'name': 'borrow', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'address', 'name': 'account', + 'type': 'address'}], + 'name': 'borrowBalanceCurrent', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [{'internalType': 'address', 'name': 'account', + 'type': 'address'}], + 'name': 'borrowBalanceStored', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'borrowIndex', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'borrowRatePerBlock', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'comptroller', + 'outputs': [{'internalType': 'contract ComptrollerInterface', + 'name': '', 'type': 'address'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'decimals', + 'outputs': [{'internalType': 'uint8', 'name': '', + 'type': 'uint8'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'bytes', 'name': 'data', + 'type': 'bytes'}], + 'name': 'delegateToImplementation', + 'outputs': [{'internalType': 'bytes', 'name': '', + 'type': 'bytes'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [{'internalType': 'bytes', 'name': 'data', + 'type': 'bytes'}], + 'name': 'delegateToViewImplementation', + 'outputs': [{'internalType': 'bytes', 'name': '', + 'type': 'bytes'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [], + 'name': 'exchangeRateCurrent', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'exchangeRateStored', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [{'internalType': 'address', 'name': 'account', + 'type': 'address'}], + 'name': 'getAccountSnapshot', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}, {'internalType': 'uint256', + 'name': '', 'type': 'uint256'}, + {'internalType': 'uint256', 'name': '', + 'type': 'uint256'}, {'internalType': 'uint256', + 'name': '', 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'getCash', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'implementation', + 'outputs': [{'internalType': 'address', 'name': '', + 'type': 'address'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'interestRateModel', + 'outputs': [{'internalType': 'contract InterestRateModel', + 'name': '', 'type': 'address'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'isCToken', + 'outputs': [{'internalType': 'bool', 'name': '', 'type': 'bool' + }], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'address', 'name': 'borrower', + 'type': 'address'}, {'internalType': 'uint256', + 'name': 'repayAmount', 'type': 'uint256'}, + {'internalType': 'contract CTokenInterface', + 'name': 'cTokenCollateral', 'type': 'address'}], + 'name': 'liquidateBorrow', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'uint256', 'name': 'mintAmount', + 'type': 'uint256'}], + 'name': 'mint', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'name', + 'outputs': [{'internalType': 'string', 'name': '', + 'type': 'string'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'pendingAdmin', + 'outputs': [{'internalType': 'address payable', 'name': '', + 'type': 'address'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'uint256', 'name': 'redeemTokens', + 'type': 'uint256'}], + 'name': 'redeem', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'uint256', 'name': 'redeemAmount', + 'type': 'uint256'}], + 'name': 'redeemUnderlying', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'uint256', 'name': 'repayAmount', + 'type': 'uint256'}], + 'name': 'repayBorrow', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'reserveFactorMantissa', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'address', 'name': 'liquidator', + 'type': 'address'}, {'internalType': 'address', + 'name': 'borrower', 'type': 'address'}, + {'internalType': 'uint256', 'name': 'seizeTokens', + 'type': 'uint256'}], + 'name': 'seize', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'supplyRatePerBlock', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'symbol', + 'outputs': [{'internalType': 'string', 'name': '', + 'type': 'string'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'totalBorrows', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [], + 'name': 'totalBorrowsCurrent', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'totalReserves', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'totalSupply', + 'outputs': [{'internalType': 'uint256', 'name': '', + 'type': 'uint256'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'address', 'name': 'dst', + 'type': 'address'}, {'internalType': 'uint256', + 'name': 'amount', 'type': 'uint256'}], + 'name': 'transfer', + 'outputs': [{'internalType': 'bool', 'name': '', 'type': 'bool' + }], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': False, + 'inputs': [{'internalType': 'address', 'name': 'src', + 'type': 'address'}, {'internalType': 'address', + 'name': 'dst', 'type': 'address'}, + {'internalType': 'uint256', 'name': 'amount', + 'type': 'uint256'}], + 'name': 'transferFrom', + 'outputs': [{'internalType': 'bool', 'name': '', 'type': 'bool' + }], + 'payable': False, + 'stateMutability': 'nonpayable', + 'type': 'function', + }, + { + 'constant': True, + 'inputs': [], + 'name': 'underlying', + 'outputs': [{'internalType': 'address', 'name': '', + 'type': 'address'}], + 'payable': False, + 'stateMutability': 'view', + 'type': 'function', + }, +] diff --git a/gnosis/eth/oracles/oracles.py b/gnosis/eth/oracles/oracles.py index ce4402fbe..9fc809a23 100644 --- a/gnosis/eth/oracles/oracles.py +++ b/gnosis/eth/oracles/oracles.py @@ -22,6 +22,7 @@ get_uniswap_v2_router_contract) from .abis.aave_abis import AAVE_ATOKEN_ABI from .abis.balancer_abis import balancer_pool_abi +from .abis.cream_abis import cream_ctoken_abi from .abis.mooniswap_abis import mooniswap_abi from .abis.zerion_abis import ZERION_TOKEN_ADAPTER_ABI from .helpers.curve_gauge_list import CURVE_GAUGE_TO_LP_TOKEN @@ -299,6 +300,7 @@ def calculate_pair_address(self, token_address: str, token_address_2: str): Calculate pair address without querying blockchain. https://uniswap.org/docs/v2/smart-contract-integration/getting-pair-addresses/#docs-header + :param token_address: :param token_address_2: :return: Checksummed address for token pair. It could be not created yet @@ -427,7 +429,7 @@ class AaveOracle(PriceOracle): def __init__(self, ethereum_client: EthereumClient, price_oracle: PriceOracle): """ :param ethereum_client: - :param price_oracle: Price oracle to get the price for the components of the Balancer Pool, UniswapV2 is + :param price_oracle: Price oracle to get the price for the components of Aave Tokens, UniswapV2 is recommended """ self.ethereum_client = ethereum_client @@ -447,6 +449,28 @@ def get_price(self, token_address: str) -> float: raise CannotGetPriceFromOracle(f'Cannot get price for {token_address}. It is not an Aaave atoken') +class CreamOracle(PriceOracle): + def __init__(self, ethereum_client: EthereumClient, price_oracle: PriceOracle): + """ + :param ethereum_client: + :param price_oracle: Price oracle to get the price for the components of Cream Tokens, UniswapV2 is + recommended + """ + self.ethereum_client = ethereum_client + self.w3 = ethereum_client.w3 + self.price_oracle = price_oracle + + def get_price(self, token_address: str) -> float: + try: + underlying_token = self.w3.eth.contract( + token_address, + abi=cream_ctoken_abi + ).functions.underlying().call() + return self.price_oracle.get_price(underlying_token) + except (ValueError, BadFunctionCallOutput, DecodingError): + raise CannotGetPriceFromOracle(f'Cannot get price for {token_address}. It is not a Cream cToken') + + class ZerionComposedOracle(ComposedPriceOracle): ZERION_ADAPTER_ADDRESS = None diff --git a/gnosis/eth/tests/test_oracles.py b/gnosis/eth/tests/test_oracles.py index 1e2b04271..84d5a6e8e 100644 --- a/gnosis/eth/tests/test_oracles.py +++ b/gnosis/eth/tests/test_oracles.py @@ -6,11 +6,11 @@ from eth_account import Account from .. import EthereumClient -from ..oracles import (BalancerOracle, CannotGetPriceFromOracle, CurveOracle, - KyberOracle, MooniswapOracle, SushiswapOracle, - UniswapOracle, UniswapV2Oracle, YearnOracle) -from ..oracles.oracles import (AaveOracle, EnzymeOracle, PoolTogetherOracle, - ZerionComposedOracle) +from ..oracles import (AaveOracle, BalancerOracle, CannotGetPriceFromOracle, + CreamOracle, CurveOracle, EnzymeOracle, KyberOracle, + MooniswapOracle, PoolTogetherOracle, SushiswapOracle, + UniswapOracle, UniswapV2Oracle, YearnOracle, + ZerionComposedOracle) from .ethereum_test_case import EthereumTestCaseMixin from .utils import just_test_if_mainnet_node @@ -182,6 +182,29 @@ def test_get_token_price(self): aave_oracle.get_price(Account.create().address) +class TestCreamOracle(EthereumTestCaseMixin, TestCase): + def test_get_price(self): + mainnet_node = just_test_if_mainnet_node() + ethereum_client = EthereumClient(mainnet_node) + sushi_oracle = SushiswapOracle(ethereum_client) + cream_oracle = CreamOracle(ethereum_client, sushi_oracle) + + cyusdc_address = '0x76Eb2FE28b36B3ee97F3Adae0C69606eeDB2A37c' + price = cream_oracle.get_price(cyusdc_address) + self.assertGreater(price, 0.) + + cydai_address = '0x8e595470Ed749b85C6F7669de83EAe304C2ec68F' + price = cream_oracle.get_price(cydai_address) + self.assertGreater(price, 0.) + + error_message = 'It is not a Cream cToken' + with self.assertRaisesMessage(CannotGetPriceFromOracle, error_message): + cream_oracle.get_price(gno_token_mainnet_address) + + with self.assertRaisesMessage(CannotGetPriceFromOracle, error_message): + cream_oracle.get_price(Account.create().address) + + class TestCurveOracle(EthereumTestCaseMixin, TestCase): def test_get_underlying_tokens(self): curve_token_address = '0xC25a3A3b969415c80451098fa907EC722572917F' # Curve.fi DAI/USDC/USDT/sUSD diff --git a/setup.py b/setup.py index fc82f54ce..353a6aa04 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ setup( name='gnosis-py', - version='3.4.4', + version='3.4.5', packages=find_packages(), package_data={'gnosis': ['py.typed']}, install_requires=requirements,