Repository: ethereum/web3.py

Issue:
Can not parse tuple[][] ABI type
* Version: 5.29.2
* Python: 3.7.3
* OS: osx
* `pip freeze` output

```
aiohttp==3.8.1
aiosignal==1.2.0
alabaster==0.7.12
anaconda-client==1.7.2
anaconda-navigator==1.9.7
anaconda-project==0.8.3
anticaptchaofficial==1.0.34
apns2==0.7.2
appnope==0.1.0
appscript==1.0.1
asn1crypto==0.24.0
astroid==2.2.5
astropy==3.2.1
async-generator==1.10
async-timeout==4.0.2
asynctest==0.13.0
atomicwrites==1.3.0
attrs==21.2.0
Babel==2.7.0
backcall==0.1.0
backports.functools-lru-cache==1.5
backports.os==0.1.1
backports.shutil-get-terminal-size==1.0.0
backports.tempfile==1.0
backports.weakref==1.0.post1
base58==2.1.1
beautifulsoup4==4.7.1
bitarray==1.2.2
bkcharts==0.2
bleach==3.1.0
blocknative-sdk==0.2.5
bokeh==1.2.0
boto==2.49.0
Bottleneck==1.2.1
certifi==2019.6.16
cffi==1.12.3
chardet==3.0.4
charset-normalizer==2.0.11
Click==7.0
cloudpickle==1.2.1
clyent==1.2.2
colorama==0.4.1
conda==4.7.10
conda-build==3.18.8
conda-package-handling==1.3.11
conda-verify==3.4.2
contextlib2==0.5.5
cryptography==2.7
cycler==0.10.0
Cython==0.29.12
cytoolz==0.11.2
dask==2.1.0
decorator==4.4.0
defusedxml==0.6.0
distributed==2.1.0
dnspython==2.2.0
docutils==0.14
entrypoints==0.3
et-xmlfile==1.0.1
eth-abi==2.1.1
eth-account==0.5.8
eth-hash==0.3.2
eth-keyfile==0.5.1
eth-keys==0.3.4
eth-rlp==0.3.0
eth-typing==2.3.0
eth-utils==1.10.0
fake-useragent==0.1.11
fastcache==1.1.0
filelock==3.0.12
Flask==1.1.1
frozenlist==1.3.0
future==0.17.1
gevent==1.4.0
glob2==0.7
gmpy2==2.0.8
greenlet==0.4.15
h11==0.12.0
h2==2.6.2
h5py==2.9.0
heapdict==1.0.0
hexbytes==0.2.2
hpack==3.0.0
html5lib==1.0.1
hyper==0.7.0
hyperframe==3.2.0
idna==3.2
imageio==2.5.0
imagesize==1.1.0
importlib-metadata==0.17
importlib-resources==5.8.0
ipfshttpclient==0.8.0a2
ipykernel==5.1.1
ipython==7.6.1
ipython-genutils==0.2.0
ipywidgets==7.5.0
isort==4.3.21
itsdangerous==1.1.0
jdcal==1.4.1
jedi==0.13.3
Jinja2==2.10.1
joblib==0.13.2
json5==0.8.4
jsonschema==4.6.0
jupyter==1.0.0
jupyter-client==5.3.1
jupyter-console==6.0.0
jupyter-core==4.5.0
jupyterlab==1.0.2
jupyterlab-server==1.0.0
keyring==18.0.0
kiwisolver==1.1.0
lazy-object-proxy==1.4.1
libarchive-c==2.8
lief==0.9.0
llvmlite==0.29.0
locket==0.2.0
lru-dict==1.1.7
lxml==4.3.4
MarkupSafe==1.1.1
matplotlib==3.1.0
mccabe==0.6.1
mistune==0.8.4
mkl-fft==1.0.12
mkl-random==1.0.2
mkl-service==2.0.2
mock==3.0.5
more-itertools==7.0.0
mpmath==1.1.0
msgpack==0.6.1
multiaddr==0.0.9
multidict==6.0.2
multipledispatch==0.6.0
navigator-updater==0.2.1
nbconvert==5.5.0
nbformat==4.4.0
netaddr==0.8.0
networkx==2.3
nltk==3.4.4
nose==1.3.7
notebook==6.0.0
numba==0.44.1
numexpr==2.6.9
numpy==1.16.4
numpydoc==0.9.1
olefile==0.46
openpyxl==2.6.2
outcome==1.1.0
packaging==19.0
pandas==0.24.2
pandocfilters==1.4.2
parsimonious==0.8.1
parso==0.5.0
partd==1.0.0
path.py==12.0.1
pathlib2==2.3.4
patsy==0.5.1
pep8==1.7.1
pexpect==4.7.0
phxsocket==0.1.2
pickleshare==0.7.5
Pillow==6.1.0
pkginfo==1.5.0.1
pluggy==0.12.0
ply==3.11
prometheus-client==0.7.1
prompt-toolkit==2.0.9
protobuf==3.19.4
psutil==5.6.3
ptyprocess==0.6.0
py==1.8.0
pycodestyle==2.5.0
pycosat==0.6.3
pycparser==2.19
pycrypto==2.6.1
pycryptodome==3.14.1
pycurl==7.43.0.3
pyflakes==2.1.1
Pygments==2.4.2
PyJWT==1.7.1
pylint==2.3.1
pymongo==4.0.1
pyodbc==4.0.26
pyOpenSSL==19.0.0
pyparsing==2.4.0
pyrsistent==0.14.11
PySocks==1.7.0
pytest==5.0.1
pytest-arraydiff==0.3
pytest-astropy==0.5.0
pytest-doctestplus==0.3.0
pytest-openfiles==0.3.2
pytest-remotedata==0.3.1
python-dateutil==2.8.0
pytz==2019.1
PyWavelets==1.0.3
PyYAML==5.1.1
pyzmq==18.0.0
QtAwesome==0.5.7
qtconsole==4.5.1
QtPy==1.8.0
rel==0.4.7
requests==2.27.1
rlp==2.0.1
rope==0.14.0
ruamel-yaml==0.15.46
scikit-image==0.15.0
scikit-learn==0.21.2
scipy==1.3.0
seaborn==0.9.0
Send2Trash==1.5.0
simplegeneric==0.8.1
singledispatch==3.4.0.3
six==1.12.0
sniffio==1.2.0
snowballstemmer==1.9.0
sortedcollections==1.1.2
sortedcontainers==2.4.0
soupsieve==1.8
Sphinx==2.1.2
sphinxcontrib-applehelp==1.0.1
sphinxcontrib-devhelp==1.0.1
sphinxcontrib-htmlhelp==1.0.2
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.2
sphinxcontrib-serializinghtml==1.1.3
sphinxcontrib-websupport==1.1.2
spyder==3.3.6
spyder-kernels==0.5.1
SQLAlchemy==1.3.5
statsmodels==0.10.0
style==1.1.0
sympy==1.4
tables==3.5.2
tblib==1.4.0
terminado==0.8.2
testpath==0.4.2
toolz==0.10.0
tornado==6.0.3
tqdm==4.32.1
traitlets==4.3.2
trio==0.19.0
trio-websocket==0.9.2
typing-extensions==4.0.1
unicodecsv==0.14.1
update==0.0.1
urllib3==1.24.2
varint==1.0.2
wcwidth==0.1.7
web3==5.29.2
webencodings==0.5.1
websocket-client==1.3.2
websockets==9.1
Werkzeug==0.15.4
widgetsnbextension==3.5.0
wrapt==1.11.2
wsproto==1.0.0
wurlitzer==1.0.2
xlrd==1.2.0
XlsxWriter==1.1.8
xlwings==0.15.8
xlwt==1.3.0
yarl==1.7.2
zict==1.0.0
zipp==3.8.0
```


### What was wrong?

The tuple regex match is something like this (in abi.py)
```
TUPLE_TYPE_STR_RE = re.compile(r'^(tuple)(\[([1-9][0-9]*)?\])?$')
```
where it can only match 'tuple[]' or 'tuple[12]' something like this. But the Seaport contract of opensea using 'tuple[][]' structure type for `fulfillAvailableOrders` and `fulfillAvailableAdvancedOrders`, which causes the regex match failed and can not correct encoding the data. The seaport contract is

https://etherscan.io/address/0x00000000006c3852cbEf3e08E8dF289169EdE581

Please help to handle this case.


Discussion:
@wei-dai Thanks for the issue! We'll take a look at this as soon as we can.

Resolving patch:
diff --git a/web3/_utils/abi.py b/web3/_utils/abi.py
--- a/web3/_utils/abi.py
+++ b/web3/_utils/abi.py
@@ -494,7 +494,7 @@ def merge_args_and_kwargs(
         return tuple()
 
 
-TUPLE_TYPE_STR_RE = re.compile(r'^(tuple)(\[([1-9][0-9]*)?\])?$')
+TUPLE_TYPE_STR_RE = re.compile(r"^(tuple)((\[([1-9]\d*\b)?])*)??$")
 
 
 def get_tuple_type_str_parts(s: str) -> Optional[Tuple[str, Optional[str]]]:


Test patch:
diff --git a/tests/core/utilities/test_abi.py b/tests/core/utilities/test_abi.py
--- a/tests/core/utilities/test_abi.py
+++ b/tests/core/utilities/test_abi.py
@@ -21,23 +21,33 @@
     'input, expected',
     (
         # Well-formed tuple type strings
-        ('tuple', ('tuple', None)),
-        ('tuple[]', ('tuple', '[]')),
-        ('tuple[1]', ('tuple', '[1]')),
-        ('tuple[10]', ('tuple', '[10]')),
-        ('tuple[19]', ('tuple', '[19]')),
-        ('tuple[195]', ('tuple', '[195]')),
-
+        ("tuple", ("tuple", None)),
+        ("tuple[]", ("tuple", "[]")),
+        ("tuple[1]", ("tuple", "[1]")),
+        ("tuple[10]", ("tuple", "[10]")),
+        ("tuple[19]", ("tuple", "[19]")),
+        ("tuple[195]", ("tuple", "[195]")),
+        ("tuple[][]", ("tuple", "[][]")),
+        ("tuple[1][1]", ("tuple", "[1][1]")),
+        ("tuple[1][]", ("tuple", "[1][]")),
+        ("tuple[][1]", ("tuple", "[][1]")),
+        ("tuple[][][]", ("tuple", "[][][]")),
+        ("tuple[1][][]", ("tuple", "[1][][]")),
+        ("tuple[][1][]", ("tuple", "[][1][]")),
+        ("tuple[][][1]", ("tuple", "[][][1]")),
         # Malformed tuple type strings
-        ('tuple[][]', None),
-        ('tuple[1][1]', None),
-        ('tuple[0]', None),
-        ('tuple[01]', None),
-        ('tupleasfasdf', None),
-        ('uint256', None),
-        ('bool', None),
-        ('', None),
-        ('tupletuple', None),
+        ("tupleasfasdf", None),
+        ("uint256", None),
+        ("bool", None),
+        ("", None),
+        ("tupletuple", None),
+        ("tuple[0]", None),
+        ("tuple[01]", None),
+        ("tuple[][0]", None),
+        ("tuple[][01]", None),
+        ("tuple[0][][]", None),
+        ("tuple[][0][]", None),
+        ("tuple[][][0]", None),
     ),
 )
 def test_get_tuple_type_str_parts(input, expected):