From 965e5e8a8144a1a891f5388c31aeb5176ead1227 Mon Sep 17 00:00:00 2001 From: RichardAtCT Date: Sun, 31 Jul 2022 21:43:58 +0400 Subject: [PATCH] Oracle (#2) * Adding Oracle Method * Added oracle --- README.md | 14 +++++--- oneinch_py/__init__.py | 2 +- oneinch_py/main.py | 74 ++++++++++++++++++++++++++++++++++++++- oneinch_py/multicall.json | 1 + oneinch_py/oracle.json | 1 + setup.py | 8 ++--- 6 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 oneinch_py/multicall.json create mode 100644 oneinch_py/oracle.json diff --git a/README.md b/README.md index ede4424..774d32f 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -# 1inch_wrapper +# 1inch.py ![1inch.py](https://github.com/RichardAtCT/1inch_wrapper/blob/master/1inchpy.png) -1inch_wrapper is a wrapper around the 1inch swap API. It has full coverage of the swap API endpoint. All chains support by 1inch are included in the wrapper. +1inch.py is a wrapper around the 1inch API and price Oracle. It has full coverage of the swap API endpoint and All chains support by 1inch are included in the OneInchSwap and OneInchOracle methods. Package also includes a helper method to ease the submission of transactions to the network. Limited chains currently supported. ## API Documentation The full 1inch swap API docs can be found at https://docs.1inch.io/ ## Installation -Use the package manager [pip](https://pip.pypa.io/en/stable/) to install 1inch_wrapper. +Use the package manager [pip](https://pip.pypa.io/en/stable/) to install 1inch.py. ```bash pip install 1inch.py @@ -18,7 +18,7 @@ pip install 1inch.py ## Usage ```python -from oneinch_py import OneInchSwap, TransactionHelper +from oneinch_py import OneInchSwap, TransactionHelper, OneInchOracle rpc_url = "yourRPCURL.com" binance_rpc = "adifferentRPCurl.com" @@ -29,6 +29,7 @@ exchange = OneInchSwap('eth_address') bsc_exchange = OneInchSwap('eth_address', chain='binance') helper = TransactionHelper(rpc_url, public_key, private_key) bsc_helper = TransactionHelper(binance_rpc, public_key, private_key, chain='binance') +oracle = OneInchOracle(rpc_url, chain='ethereum') # See chains currently supported by the helper method: helper.chains @@ -41,6 +42,11 @@ result = helper.build_tx(result) # prepare the transaction for signing, gas pric result = helper.sign_tx(result) # sign the transaction using your private key result = helper.broadcast_tx(result) #broadcast the transaction to the network and wait for the receipt. +#USDT to ETH price on the Oracle. Note that you need to indicate the token decimal if it is anything other than 18. +oracle.get_rate_to_ETH("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", src_token_decimal=6) + +# Get the rate between any two tokens. +oracle.get_rate(src_token="0x6B175474E89094C44Da98b954EedeAC495271d0F", dst_token="0x111111111117dC0aa78b770fA6A738034120C302") exchange.health_check() # 'OK' diff --git a/oneinch_py/__init__.py b/oneinch_py/__init__.py index 02136a2..864643d 100644 --- a/oneinch_py/__init__.py +++ b/oneinch_py/__init__.py @@ -1 +1 @@ -from oneinch_py.main import OneInchSwap, TransactionHelper +from oneinch_py.main import OneInchSwap, TransactionHelper, OneInchOracle diff --git a/oneinch_py/main.py b/oneinch_py/main.py index c278b74..2c5a263 100644 --- a/oneinch_py/main.py +++ b/oneinch_py/main.py @@ -5,6 +5,7 @@ import importlib.resources as pkg_resources from functools import reduce from web3.middleware import geth_poa_middleware +from eth_abi import encode class UnknownToken(Exception): @@ -195,7 +196,6 @@ def get_approve(self, from_token_symbol: str, amount=None): class TransactionHelper: - gas_oracles = { # "ethereum": 'https://etherchain.org/api/gasnow', "binance": 'https://gbsc.blockscan.com/gasapi.ashx?apikey=key&method=gasoracle', @@ -295,5 +295,77 @@ def get_ERC20_balance(self, contract_address, decimal=None): return balance_in_wei / 10 ** decimal +class OneInchOracle: + chains = { + "ethereum": '1', + "binance": '56', + "polygon": "137", + "optimism": "10", + "arbitrum": "42161", + "gnosis": "100", + "avalanche": "43114", + "fantom": "250" + } + + contracts = { + "ethereum": '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb', + "binance": '0xfbD61B037C325b959c0F6A7e69D8f37770C2c550', + "polygon": "0x7F069df72b7A39bCE9806e3AfaF579E54D8CF2b9", + "optimism": "0x11DEE30E710B8d4a8630392781Cc3c0046365d4c", + "arbitrum": "0x735247fb0a604c0adC6cab38ACE16D0DbA31295F", + "gnosis": "0x142DB045195CEcaBe415161e1dF1CF0337A4d02E", + "avalanche": "0xBd0c7AaF0bF082712EbE919a9dD94b2d978f79A9", + "fantom": "0xE8E598A1041b6fDB13999D275a202847D9b654ca" + } + + # multicall_address = "0xDA3C19c6Fe954576707fA24695Efb830D9ccA1CA" + + oracle_abi = json.loads(pkg_resources.read_text(__package__, 'oracle.json'))['result'] + # multicall_abi = json.loads(pkg_resources.read_text(__package__, 'multicall.json'))['result'] + + def __init__(self, rpc_url, chain='ethereum'): + self.w3 = Web3(Web3.HTTPProvider(rpc_url)) + self.chain = chain + self.chain_id = self.chains[chain] + self.contract_address = self.contracts[chain] + self.oracle_contract = self.w3.eth.contract(address=self.contract_address, abi=self.oracle_abi) + # self.multicall_contract = self.w3.eth.contract(address=self.multicall_address, abi=self.multicall_abi) + + def get_rate(self, src_token, dst_token, wrap=False, src_token_decimal: int = 18, dst_token_decimal: int = 18): + rate = self.oracle_contract.functions.getRate(self.w3.toChecksumAddress(src_token), + self.w3.toChecksumAddress(dst_token), wrap).call() + if src_token_decimal == 18 and dst_token_decimal < 18: + rate = rate / 10 ** dst_token_decimal + elif dst_token_decimal == 18 and src_token_decimal < 18: + rate = rate / 10 ** ((18 - src_token_decimal) + 18) + elif dst_token_decimal < 18 and src_token_decimal < 18: + rate = rate / 10 ** ((18 - src_token_decimal) + (18 - dst_token_decimal)) + else: + rate = rate / 10 ** 18 + return rate + + def get_rate_to_ETH(self, src_token, wrap=False, src_token_decimal=18): + rate = self.oracle_contract.functions.getRateToEth(self.w3.toChecksumAddress(src_token), wrap).call() + if src_token_decimal == 18: + rate = rate / 10 ** 18 + elif src_token_decimal < 18: + rate = rate / 10 ** ((18 - src_token_decimal) + 18) + return rate +# TODO Figure this all out at some point + # def get_multicall(self, token_list): + # for address in token_list: + # call_data = { + # "to": "0x07D91f5fb9Bf7798734C3f606dB065549F6893bb", + # "data": f"{self.oracle_contract.functions.getRateToEth(address,True)}" + # } + # + # print(call_data) + # # mapped = map(lambda , token_list, wrap_list) + # # mapped = list(mapped) + # # rate = self.multicall_contract.functions.multicall(mapped).call() + # return + + + if __name__ == '__main__': pass diff --git a/oneinch_py/multicall.json b/oneinch_py/multicall.json new file mode 100644 index 0000000..1ee6a35 --- /dev/null +++ b/oneinch_py/multicall.json @@ -0,0 +1 @@ +{"status":"1","message":"OK-Missing/Invalid API Key, rate limit of 1/5sec applied","result":"[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"struct MultiCall.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"multicall\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"results\",\"type\":\"bytes[]\"},{\"internalType\":\"bool[]\",\"name\":\"success\",\"type\":\"bool[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"} \ No newline at end of file diff --git a/oneinch_py/oracle.json b/oneinch_py/oracle.json new file mode 100644 index 0000000..ba405b1 --- /dev/null +++ b/oneinch_py/oracle.json @@ -0,0 +1 @@ +{"status":"1","message":"OK-Missing/Invalid API Key, rate limit of 1/5sec applied","result":"[{\"inputs\":[{\"internalType\":\"contract MultiWrapper\",\"name\":\"_multiWrapper\",\"type\":\"address\"},{\"internalType\":\"contract IOracle[]\",\"name\":\"existingOracles\",\"type\":\"address[]\"},{\"internalType\":\"enum OffchainOracle.OracleType[]\",\"name\":\"oracleTypes\",\"type\":\"uint8[]\"},{\"internalType\":\"contract IERC20[]\",\"name\":\"existingConnectors\",\"type\":\"address[]\"},{\"internalType\":\"contract IERC20\",\"name\":\"wBase\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract IERC20\",\"name\":\"connector\",\"type\":\"address\"}],\"name\":\"ConnectorAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract IERC20\",\"name\":\"connector\",\"type\":\"address\"}],\"name\":\"ConnectorRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract MultiWrapper\",\"name\":\"multiWrapper\",\"type\":\"address\"}],\"name\":\"MultiWrapperUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract IOracle\",\"name\":\"oracle\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enum OffchainOracle.OracleType\",\"name\":\"oracleType\",\"type\":\"uint8\"}],\"name\":\"OracleAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contract IOracle\",\"name\":\"oracle\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enum OffchainOracle.OracleType\",\"name\":\"oracleType\",\"type\":\"uint8\"}],\"name\":\"OracleRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"connector\",\"type\":\"address\"}],\"name\":\"addConnector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IOracle\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"enum OffchainOracle.OracleType\",\"name\":\"oracleKind\",\"type\":\"uint8\"}],\"name\":\"addOracle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"connectors\",\"outputs\":[{\"internalType\":\"contract IERC20[]\",\"name\":\"allConnectors\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"srcToken\",\"type\":\"address\"},{\"internalType\":\"contract IERC20\",\"name\":\"dstToken\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"useWrappers\",\"type\":\"bool\"}],\"name\":\"getRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"weightedRate\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"srcToken\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"useSrcWrappers\",\"type\":\"bool\"}],\"name\":\"getRateToEth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"weightedRate\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"multiWrapper\",\"outputs\":[{\"internalType\":\"contract MultiWrapper\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracles\",\"outputs\":[{\"internalType\":\"contract IOracle[]\",\"name\":\"allOracles\",\"type\":\"address[]\"},{\"internalType\":\"enum OffchainOracle.OracleType[]\",\"name\":\"oracleTypes\",\"type\":\"uint8[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"connector\",\"type\":\"address\"}],\"name\":\"removeConnector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IOracle\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"enum OffchainOracle.OracleType\",\"name\":\"oracleKind\",\"type\":\"uint8\"}],\"name\":\"removeOracle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract MultiWrapper\",\"name\":\"_multiWrapper\",\"type\":\"address\"}],\"name\":\"setMultiWrapper\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"} \ No newline at end of file diff --git a/setup.py b/setup.py index 34fd05a..a7bd947 100644 --- a/setup.py +++ b/setup.py @@ -8,16 +8,16 @@ setup( name='1inch.py', - version='1.5.0', + version='1.6.1', url='https://github.com/RichardAtCT/1inch_wrapper', long_description_content_type="text/markdown", long_description=long_description, keywords="1inch, wrapper, aggregator, DEX", packages=find_packages(include=['oneinch_py', 'oneinch_py.*']), install_requires=[ - 'requests~=2.28.1', - 'web3~=5.30.0', - 'setuptools~=57.0.0'], + 'requests>=2.28.1', + 'web3>=5.30.0', + 'setuptools>=57.0.0'], python_requires=">=3.7, <4", license='MIT', author='RichardAt',