Skip to content

Commit

Permalink
feat: dank_web3 helper (#49)
Browse files Browse the repository at this point in the history
* feat: dank_web3 convenience obj

* feat: adapt patch_contract fn to new dank_web3 helper

* fix(test): adapt tests to new dank_web3 object

* chore: update readme
  • Loading branch information
BobTheBuidler authored Feb 24, 2024
1 parent c30731a commit 8063788
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 33 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@ To install Dank Mids, use pip:

### Usage with web3.py

The primary function you need to use Dank Mids is `setup_dank_w3_from_sync`. This function takes a sync Web3 instance and wraps it for async use.
The primary function you need to use Dank Mids is `setup_dank_w3_from_sync`. This function takes a sync Web3 instance and wraps it for async use. If using dank_mids with eth-brownie, you can just import the premade dank_web3 object as well

Example usage of Dank Mids with web3py:

```python
from dank_mids import setup_dank_w3_from_sync
dank_w3 = setup_dank_w3_from_sync(w3)
random_block = await dank_w3.eth.get_block(123)
from dank_mids.helpers import setup_dank_w3_from_sync
dank_web3 = setup_dank_w3_from_sync(w3)
# OR
from dank_mids.helpers import dank_web3

# Then:
random_block = await dank_web3.eth.get_block(123)
```

### Usage with eth-brownie
Expand Down
4 changes: 4 additions & 0 deletions dank_mids/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from dank_mids.helpers import setup_dank_w3, setup_dank_w3_from_sync
from dank_mids.middleware import dank_middleware

try:
from dank_mids.brownie_patch import dank_web3, patch_contract
except ImportError:
pass

def _configure_concurrent_future_work_queue_size():
import concurrent.futures.process as _cfp
Expand Down
11 changes: 10 additions & 1 deletion dank_mids/brownie_patch/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@

from dank_mids.brownie_patch.contract import patch_contract
from dank_mids.helpers import setup_dank_w3_from_sync

# If using dank_mids wih brownie, and brownie is connected when this file executes, you will get a 'dank_w3' async web3 instance with Dank Middleware here.
try:
from brownie import network, web3
if network.is_connected():
from dank_mids.brownie_patch.contract import patch_contract
dank_web3 = setup_dank_w3_from_sync(web3)
except ImportError:
pass
11 changes: 5 additions & 6 deletions dank_mids/brownie_patch/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from types import MethodType
from typing import Optional, Union

from brownie import Contract, network, web3
from brownie import Contract, network
from brownie.network.contract import ContractCall, ContractTx, OverloadedMethod
from web3 import Web3

Expand All @@ -17,11 +17,10 @@ def _patch_if_method(method: ContractMethod, w3: Web3) -> None:
elif isinstance(method, OverloadedMethod):
_patch_overloaded_method(method, w3)


def patch_contract(contract: Contract, w3: Optional[Web3]) -> Contract:
if w3 is None and network.is_connected():
w3 = web3
assert w3 is not None, "You must make sure either brownie is connected or you pass in a Web3 instance."
def patch_contract(contract: Contract, w3: Optional[Web3] = None) -> Contract:
if w3 is None:
assert network.is_connected(), "You must make sure either brownie is connected or you pass in a Web3 instance."
from dank_mids.helpers import dank_web3 as w3
for k, v in contract.__dict__.items():
_patch_if_method(v, w3)
return contract
4 changes: 2 additions & 2 deletions dank_mids/helpers/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async def set_done_wrap(self: "RPCRequest", *args: P.args, **kwargs: P.kwargs) -
retval = await fn(self, *args, **kwargs)
self._done.set()
return retval
return set_done_wrap
return set_done_wrap

# Everything below is in web3.py now, but dank_mids currently needs a version that predates them.

Expand Down Expand Up @@ -165,4 +165,4 @@ def _format_response(
elif "error" in response and method in error_formatters:
return _format_response("error", error_formatters[method])
else:
return response
return response
5 changes: 0 additions & 5 deletions tests/fixtures.py

This file was deleted.

14 changes: 7 additions & 7 deletions tests/test_brownie_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,37 @@
from brownie import Contract, web3
from multicall.utils import await_awaitable

from dank_mids import setup_dank_w3_from_sync
from dank_mids.brownie_patch import patch_contract
from dank_mids import dank_web3, patch_contract, setup_dank_w3_from_sync
from dank_mids.brownie_patch.call import _patch_call
from tests.fixtures import dank_w3


def test_patch_call():
# must use from_explorer for gh testing workflow
weth = Contract.from_explorer('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')
_patch_call(weth.totalSupply, dank_w3)
_patch_call(weth.totalSupply, dank_web3)
assert hasattr(weth.totalSupply, 'coroutine')
assert await_awaitable(weth.totalSupply.coroutine(block_identifier=13_000_000)) == 6620041514474872981393155

def test_gather():
# must use from_explorer for gh testing workflow
weth = Contract.from_explorer('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')
_patch_call(weth.totalSupply, dank_w3)
_patch_call(weth.totalSupply, dank_web3)
assert hasattr(weth.totalSupply, 'coroutine')
for result in await_awaitable(asyncio.gather(*[weth.totalSupply.coroutine(block_identifier=13_000_000) for _ in range(10_000)])):
assert result == 6620041514474872981393155

def test_patch_contract():
# ContractCall
# must use from_explorer for gh testing workflow
weth = patch_contract(Contract.from_explorer('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), dank_w3)
# specify w3
weth = patch_contract(Contract.from_explorer('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'), dank_web3)
assert hasattr(weth.totalSupply, 'coroutine')
assert await_awaitable(weth.totalSupply.coroutine(block_identifier=13_000_000)) == 6620041514474872981393155

# ContractTx
# must use from_explorer for gh testing workflow
uni_v3_quoter = patch_contract(Contract.from_explorer('0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6'), dank_w3)
# dont specify w3
uni_v3_quoter = patch_contract(Contract.from_explorer('0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6'))
assert hasattr(uni_v3_quoter.quoteExactInput, 'coroutine')
assert await_awaitable(
uni_v3_quoter.quoteExactInput.coroutine(b"\xc0*\xaa9\xb2#\xfe\x8d\n\x0e\\O'\xea\xd9\x08<ul\xc2\x00\x01\xf4\xa0\xb8i\x91\xc6!\x8b6\xc1\xd1\x9dJ.\x9e\xb0\xce6\x06\xebH", 1e18, block_identifier=13_000_000)
Expand Down
15 changes: 7 additions & 8 deletions tests/test_dank_mids.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
from multicall.utils import await_awaitable, gather
from web3._utils.rpc_abi import RPC

from dank_mids import instances
from tests.fixtures import dank_w3
from dank_mids import dank_web3, instances

CHAI = '0x06AF07097C9Eeb7fD685c692751D5C66dB49c215'
height = chain.height
BIG_WORK = [Call(CHAI, 'totalSupply()(uint)', [[f'totalSupply{i}',None]], block_id=height - (i // 25000), _w3=dank_w3).coroutine() for i in range(100_000)]
BIG_WORK = [Call(CHAI, 'totalSupply()(uint)', [[f'totalSupply{i}',None]], block_id=height - (i // 25000), _w3=dank_web3).coroutine() for i in range(100_000)]
height = chain.height
MULTIBLOCK_WORK = [Call(CHAI, 'totalSupply()(uint)', [[f'totalSupply{i}',None]], _w3=dank_w3, block_id=height-i).coroutine() for i in range(100_000)]
MULTIBLOCK_WORK = [Call(CHAI, 'totalSupply()(uint)', [[f'totalSupply{i}',None]], _w3=dank_web3, block_id=height-i).coroutine() for i in range(100_000)]


def _get_controller():
Expand Down Expand Up @@ -56,13 +55,13 @@ def test_next_bid():
assert _get_controller().multicall_uid.next + 1 == _get_controller().multicall_uid.next

def test_other_methods():
work = [dank_w3.eth.get_block_number() for i in range(50)]
work.append(dank_w3.eth.get_block('0xe25822'))
work.append(dank_w3.manager.coro_request(RPC.web3_clientVersion, []))
work = [dank_web3.eth.get_block_number() for i in range(50)]
work.append(dank_web3.eth.get_block('0xe25822'))
work.append(dank_web3.manager.coro_request(RPC.web3_clientVersion, []))
assert await_awaitable(gather(work))

def test_AttributeDict():
block = await_awaitable(dank_w3.eth.get_block("0xe25822"))
block = await_awaitable(dank_web3.eth.get_block("0xe25822"))
assert block['timestamp']
assert block.timestamp

Expand Down

0 comments on commit 8063788

Please sign in to comment.