Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

tests: switch to ganache v7#201

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
ErikBjare merged 4 commits intomasterfromdev/ganache-v7
Dec 21, 2021
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion.github/workflows/test.yml
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,7 +48,8 @@ jobs:
- name: Install dependencies
run: |
poetry install
npm install -g ganache-cli
# TODO: Update to stable ganache when released!
npm install -g ganache@beta
- name: Test
env:
PROVIDER: ${{ secrets.MAINNET_PROVIDER }}
Expand Down
2 changes: 1 addition & 1 deletionMakefile
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
.PHONY: test typecheck lint precommit docs

test:
poetry run pytest -v --cov=uniswap --cov-report html --cov-report term --cov-report xml
poetry run pytest -v --tb=line --maxfail=4 --cov=uniswap --cov-report html --cov-report term --cov-report xml

typecheck:
poetry run mypy --pretty
Expand Down
4 changes: 4 additions & 0 deletionspyproject.toml
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,6 +39,10 @@ Sphinx = "*"
sphinx-book-theme = "*"
sphinx-click = "*"

[tool.pytest.ini_options]
log_cli = false # to print logs during tests, set to true
#log_level = "NOTSET"

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
42 changes: 30 additions & 12 deletionstests/test_uniswap.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,13 +18,16 @@


logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)

ENV_UNISWAP_VERSION = os.getenv("UNISWAP_VERSION", None)
if ENV_UNISWAP_VERSION:
UNISWAP_VERSIONS = [int(ENV_UNISWAP_VERSION)]
else:
UNISWAP_VERSIONS = [1, 2, 3]

RECEIPT_TIMEOUT = 5


@dataclass
class GanacheInstance:
Expand All@@ -36,7 +39,11 @@ class GanacheInstance:
@pytest.fixture(scope="module", params=UNISWAP_VERSIONS)
def client(request, web3: Web3, ganache: GanacheInstance):
return Uniswap(
ganache.eth_address, ganache.eth_privkey, web3=web3, version=request.param
ganache.eth_address,
ganache.eth_privkey,
web3=web3,
version=request.param,
use_estimate_gas=False, # see note in _build_and_send_tx
)


Expand All@@ -54,35 +61,46 @@ def test_assets(client: Uniswap):
logger.info("Buying...")

tx = client.make_trade_output(tokens["ETH"], token_addr, amount)
client.w3.eth.wait_for_transaction_receipt(tx)
client.w3.eth.wait_for_transaction_receipt(tx, timeout=RECEIPT_TIMEOUT)


@pytest.fixture(scope="module")
def web3(ganache: GanacheInstance):
w3 = Web3(Web3.HTTPProvider(ganache.provider, request_kwargs={"timeout":60}))
w3 = Web3(Web3.HTTPProvider(ganache.provider, request_kwargs={"timeout":30}))
if 1 != int(w3.net.version):
raise Exception("PROVIDER was not a mainnet provider, which the tests require")
return w3


@pytest.fixture(scope="module")
def ganache() -> Generator[GanacheInstance, None, None]:
"""Fixture that runs ganache-cli which has forked off mainnet"""
if not shutil.which("ganache-cli"):
"""Fixture that runs ganache which has forked off mainnet"""
if not shutil.which("ganache"):
raise Exception(
"ganache-cli was not found in PATH, you can install it with `npm install -g ganache-cli`"
"ganache was not found in PATH, you can install it with `npm install -g ganache`"
)
if "PROVIDER" not in os.environ:
raise Exception(
"PROVIDER was not set, you need to set it to a mainnet provider (such as Infura) so that we can fork off our testnet"
)

port = 10999
defaultGasPrice = 1000_000_000_000 # 1000 gwei
p = subprocess.Popen(
f"ganache-cli --port {port} -s test --networkId 1 --fork {os.environ['PROVIDER']}",
f"""ganache
--port {port}
--wallet.seed test
--chain.networkId 1
--chain.chainId 1
--fork.url {os.environ['PROVIDER']}
--miner.defaultGasPrice {defaultGasPrice}
--miner.legacyInstamine true
""".replace(
"\n", " "
),
shell=True,
)
# Address #1 when ganache is run with `-s test`, it starts with100 ETH
# Address #1 when ganache is run with `--wallet.seed test`, it starts with1000 ETH
eth_address = "0x94e3361495bD110114ac0b6e35Ed75E77E6a6cFA"
eth_privkey = "0x6f1313062db38875fb01ee52682cbf6a8420e92bfbc578c5d4fdc0a32c50266f"
sleep(3)
Expand All@@ -105,7 +123,7 @@ class TestUniswap(object):
ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"

# TODO: Detect mainnet vs rinkeby and set accordingly, like _get_token_addresses in the Uniswap class
# For Mainnet testing (with `ganache-cli --fork` as per the ganache fixture)
# For Mainnet testing (with `ganache --fork` as per the ganache fixture)
eth = "0x0000000000000000000000000000000000000000"
weth = Web3.toChecksumAddress("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
bat = Web3.toChecksumAddress("0x0D8775F648430679A709E98d2b0Cb6250d2887EF")
Expand DownExpand Up@@ -219,7 +237,7 @@ def get_exchange_rate(
)
def test_add_liquidity(self, client: Uniswap, web3: Web3, token, max_eth):
r = client.add_liquidity(token, max_eth)
tx = web3.eth.wait_for_transaction_receipt(r, timeout=6000)
tx = web3.eth.wait_for_transaction_receipt(r, timeout=RECEIPT_TIMEOUT)
assert tx["status"]

@pytest.mark.skip
Expand DownExpand Up@@ -274,7 +292,7 @@ def test_make_trade(
bal_in_before = client.get_token_balance(input_token)

txid = client.make_trade(input_token, output_token, qty, recipient)
tx = web3.eth.wait_for_transaction_receipt(txid)
tx = web3.eth.wait_for_transaction_receipt(txid, timeout=RECEIPT_TIMEOUT)
assert tx["status"]

# TODO: Checks for ETH, taking gas into account
Expand DownExpand Up@@ -324,7 +342,7 @@ def test_make_trade_output(
balance_before = client.get_token_balance(output_token)

r = client.make_trade_output(input_token, output_token, qty, recipient)
tx = web3.eth.wait_for_transaction_receipt(r, timeout=30)
tx = web3.eth.wait_for_transaction_receipt(r, timeout=RECEIPT_TIMEOUT)
assert tx["status"]

# TODO: Checks for ETH, taking gas into account
Expand Down
79 changes: 52 additions & 27 deletionsuniswap/uniswap.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -45,6 +45,16 @@ class Uniswap:
Wrapper around Uniswap contracts.
"""

address: AddressLike
version: int

w3: Web3
netid: int
netname: str

default_slippage: float
use_estimate_gas: bool

def __init__(
self,
address: Union[AddressLike, str, None],
Expand All@@ -53,6 +63,8 @@ def __init__(
web3: Web3 = None,
version: int = 1,
default_slippage: float = 0.01,
use_estimate_gas: bool = True,
# use_eip1559: bool = True,
factory_contract_addr: str = None,
router_contract_addr: str = None,
) -> None:
Expand All@@ -66,7 +78,7 @@ def __init__(
:param factory_contract_addr: Can be optionally set to override the address of the factory contract.
:param router_contract_addr: Can be optionally set to override the address of the router contract (v2 only).
"""
self.address: AddressLike = _str_to_addr(
self.address = _str_to_addr(
address or "0x0000000000000000000000000000000000000000"
)
self.private_key = (
Expand All@@ -78,22 +90,23 @@ def __init__(

# TODO: Write tests for slippage
self.default_slippage = default_slippage
self.use_estimate_gas = use_estimate_gas

if web3:
self.w3 = web3
else:
# Initialize web3. Extra provider for testing.
self.provider = provider or os.environ["PROVIDER"]
self.w3 = Web3(
Web3.HTTPProvider(self.provider, request_kwargs={"timeout": 60})
)

netid = int(self.w3.net.version)
if netid in _netid_to_name:
self.network = _netid_to_name[netid]
if not provider:
provider = os.environ["PROVIDER"]
self.w3 =Web3(Web3.HTTPProvider(provider, request_kwargs={"timeout": 60}))

# Cache netid to avoid extra RPC calls
self.netid = int(self.w3.net.version)
ifself.netid in _netid_to_name:
self.netname = _netid_to_name[self.netid]
else:
raise Exception(f"Unknown netid: {netid}")
logger.info(f"Using {self.w3} ('{self.network}')")
raise Exception(f"Unknown netid: {self.netid}")
logger.info(f"Using {self.w3} ('{self.netname}', netid: {self.netid})")

self.last_nonce: Nonce = self.w3.eth.get_transaction_count(self.address)

Expand All@@ -102,14 +115,14 @@ def __init__(
# max_approval_check checks that current approval is above a reasonable number
# The program cannot check for max_approval each time because it decreases
# with each trade.
self.max_approval_hex = f"0x{64 * 'f'}"
self.max_approval_int = int(self.max_approval_hex, 16)
self.max_approval_check_hex = f"0x{15 * '0'}{49 * 'f'}"
self.max_approval_check_int = int(self.max_approval_check_hex, 16)
max_approval_hex = f"0x{64 * 'f'}"
self.max_approval_int = int(max_approval_hex, 16)
max_approval_check_hex = f"0x{15 * '0'}{49 * 'f'}"
self.max_approval_check_int = int(max_approval_check_hex, 16)

if self.version == 1:
if factory_contract_addr is None:
factory_contract_addr = _factory_contract_addresses_v1[self.network]
factory_contract_addr = _factory_contract_addresses_v1[self.netname]

self.factory_contract = _load_contract(
self.w3,
Expand All@@ -118,11 +131,11 @@ def __init__(
)
elif self.version == 2:
if router_contract_addr is None:
router_contract_addr = _router_contract_addresses_v2[self.network]
router_contract_addr = _router_contract_addresses_v2[self.netname]
self.router_address: AddressLike = _str_to_addr(router_contract_addr)

if factory_contract_addr is None:
factory_contract_addr = _factory_contract_addresses_v2[self.network]
factory_contract_addr = _factory_contract_addresses_v2[self.netname]
self.factory_contract = _load_contract(
self.w3,
abi_name="uniswap-v2/factory",
Expand DownExpand Up@@ -1085,8 +1098,19 @@ def _build_and_send_tx(
if not tx_params:
tx_params = self._get_tx_params()
transaction = function.buildTransaction(tx_params)
# Uniswap3 uses 20% margin for transactions
transaction["gas"] = Wei(int(self.w3.eth.estimate_gas(transaction) * 1.2))

if "gas" not in tx_params:
# `use_estimate_gas` needs to be True for networks like Arbitrum (can't assume 250000 gas),
# but it breaks tests for unknown reasons because estimateGas takes forever on some tx's.
# Maybe an issue with ganache? (got GC warnings once...)
if self.use_estimate_gas:
# The Uniswap V3 UI uses 20% margin for transactions
transaction["gas"] = Wei(
int(self.w3.eth.estimate_gas(transaction) * 1.2)
)
else:
transaction["gas"] = Wei(250000)

signed_txn = self.w3.eth.account.sign_transaction(
transaction, private_key=self.private_key
)
Expand All@@ -1098,15 +1122,18 @@ def _build_and_send_tx(
logger.debug(f"nonce: {tx_params['nonce']}")
self.last_nonce = Nonce(tx_params["nonce"] + 1)

def _get_tx_params(self, value: Wei = Wei(0)) -> TxParams:
def _get_tx_params(self, value: Wei = Wei(0), gas: Wei = None) -> TxParams:
"""Get generic transaction parameters."""
return {
params: TxParams = {
"from": _addr_to_str(self.address),
"value": value,
"nonce": max(
self.last_nonce, self.w3.eth.get_transaction_count(self.address)
),
}
if gas:
params["gas"] = gas
return params

# ------ Price Calculation Utils ---------------------------------------------------
def _calculate_max_input_token(
Expand DownExpand Up@@ -1255,14 +1282,12 @@ def _get_token_addresses(self) -> Dict[str, ChecksumAddress]:
Returns a dict with addresses for tokens for the current net.
Used in testing.
"""
netid = int(self.w3.net.version)
netname = _netid_to_name[netid]
if netname == "mainnet":
if self.netname == "mainnet":
return tokens
elif netname == "rinkeby":
elifself.netname == "rinkeby":
return tokens_rinkeby
else:
raise Exception(f"Unknown net '{netname}'")
raise Exception(f"Unknown net '{self.netname}'")

# ---- Old v1 utils ----

Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp