ccxt 4.2.77__py2.py3-none-any.whl → 4.4.49__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccxt/__init__.py +36 -14
- ccxt/abstract/alpaca.py +4 -0
- ccxt/abstract/bigone.py +1 -1
- ccxt/abstract/binance.py +112 -48
- ccxt/abstract/binancecoinm.py +112 -48
- ccxt/abstract/binanceus.py +147 -83
- ccxt/abstract/binanceusdm.py +112 -48
- ccxt/abstract/bingx.py +133 -78
- ccxt/abstract/bitbank.py +5 -0
- ccxt/abstract/bitfinex.py +136 -65
- ccxt/abstract/bitfinex1.py +69 -0
- ccxt/abstract/bitflyer.py +1 -0
- ccxt/abstract/bitget.py +8 -1
- ccxt/abstract/bitmart.py +13 -1
- ccxt/abstract/bitopro.py +1 -0
- ccxt/abstract/bitpanda.py +0 -12
- ccxt/abstract/bitrue.py +3 -3
- ccxt/abstract/bitstamp.py +26 -3
- ccxt/abstract/blofin.py +24 -0
- ccxt/abstract/btcbox.py +1 -0
- ccxt/abstract/bybit.py +29 -14
- ccxt/abstract/cex.py +28 -29
- ccxt/abstract/coinbase.py +6 -0
- ccxt/abstract/coinbaseadvanced.py +94 -0
- ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
- ccxt/abstract/coinbaseinternational.py +1 -1
- ccxt/abstract/coincatch.py +94 -0
- ccxt/abstract/coinex.py +233 -123
- ccxt/abstract/coinmetro.py +1 -0
- ccxt/abstract/cryptocom.py +14 -0
- ccxt/abstract/defx.py +69 -0
- ccxt/abstract/deribit.py +1 -0
- ccxt/abstract/digifinex.py +1 -0
- ccxt/abstract/ellipx.py +25 -0
- ccxt/abstract/gate.py +20 -0
- ccxt/abstract/gateio.py +20 -0
- ccxt/abstract/gemini.py +1 -0
- ccxt/abstract/hashkey.py +67 -0
- ccxt/abstract/hyperliquid.py +1 -1
- ccxt/abstract/independentreserve.py +6 -0
- ccxt/abstract/kraken.py +4 -3
- ccxt/abstract/krakenfutures.py +4 -0
- ccxt/abstract/kucoin.py +24 -0
- ccxt/abstract/kucoinfutures.py +34 -0
- ccxt/abstract/luno.py +2 -0
- ccxt/abstract/mexc.py +4 -0
- ccxt/abstract/myokx.py +340 -0
- ccxt/abstract/oceanex.py +5 -0
- ccxt/abstract/okx.py +30 -0
- ccxt/abstract/onetrading.py +0 -12
- ccxt/abstract/oxfun.py +34 -0
- ccxt/abstract/paradex.py +40 -0
- ccxt/abstract/phemex.py +1 -0
- ccxt/abstract/upbit.py +4 -0
- ccxt/abstract/vertex.py +19 -0
- ccxt/abstract/whitebit.py +31 -1
- ccxt/abstract/woo.py +6 -2
- ccxt/abstract/woofipro.py +119 -0
- ccxt/abstract/xt.py +153 -0
- ccxt/abstract/zonda.py +6 -0
- ccxt/ace.py +164 -60
- ccxt/alpaca.py +727 -63
- ccxt/ascendex.py +395 -249
- ccxt/async_support/__init__.py +36 -14
- ccxt/async_support/ace.py +164 -60
- ccxt/async_support/alpaca.py +727 -63
- ccxt/async_support/ascendex.py +396 -249
- ccxt/async_support/base/exchange.py +531 -155
- ccxt/async_support/base/ws/aiohttp_client.py +28 -5
- ccxt/async_support/base/ws/cache.py +3 -2
- ccxt/async_support/base/ws/client.py +26 -5
- ccxt/async_support/base/ws/fast_client.py +4 -3
- ccxt/async_support/base/ws/functions.py +1 -1
- ccxt/async_support/base/ws/future.py +40 -31
- ccxt/async_support/base/ws/order_book_side.py +3 -0
- ccxt/async_support/bequant.py +1 -1
- ccxt/async_support/bigone.py +329 -202
- ccxt/async_support/binance.py +3030 -1087
- ccxt/async_support/binancecoinm.py +2 -1
- ccxt/async_support/binanceus.py +12 -1
- ccxt/async_support/binanceusdm.py +3 -1
- ccxt/async_support/bingx.py +3205 -937
- ccxt/async_support/bit2c.py +119 -38
- ccxt/async_support/bitbank.py +215 -76
- ccxt/async_support/bitbns.py +124 -53
- ccxt/async_support/bitfinex.py +3236 -1078
- ccxt/async_support/bitfinex1.py +1711 -0
- ccxt/async_support/bitflyer.py +238 -49
- ccxt/async_support/bitget.py +1525 -573
- ccxt/async_support/bithumb.py +199 -65
- ccxt/async_support/bitmart.py +1320 -435
- ccxt/async_support/bitmex.py +308 -111
- ccxt/async_support/bitopro.py +256 -96
- ccxt/async_support/bitrue.py +365 -233
- ccxt/async_support/bitso.py +201 -89
- ccxt/async_support/bitstamp.py +438 -269
- ccxt/async_support/bitteam.py +179 -73
- ccxt/async_support/bitvavo.py +180 -70
- ccxt/async_support/bl3p.py +92 -25
- ccxt/async_support/blockchaincom.py +193 -79
- ccxt/async_support/blofin.py +392 -148
- ccxt/async_support/btcalpha.py +161 -55
- ccxt/async_support/btcbox.py +250 -34
- ccxt/async_support/btcmarkets.py +232 -85
- ccxt/async_support/btcturk.py +159 -60
- ccxt/async_support/bybit.py +2231 -1193
- ccxt/async_support/cex.py +1409 -1329
- ccxt/async_support/coinbase.py +1454 -287
- ccxt/async_support/coinbaseadvanced.py +17 -0
- ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/async_support/coinbaseinternational.py +428 -88
- ccxt/async_support/coincatch.py +5152 -0
- ccxt/async_support/coincheck.py +121 -38
- ccxt/async_support/coinex.py +4020 -3339
- ccxt/async_support/coinlist.py +273 -116
- ccxt/async_support/coinmate.py +204 -97
- ccxt/async_support/coinmetro.py +203 -110
- ccxt/async_support/coinone.py +142 -68
- ccxt/async_support/coinsph.py +223 -97
- ccxt/async_support/coinspot.py +137 -62
- ccxt/async_support/cryptocom.py +515 -185
- ccxt/async_support/currencycom.py +203 -85
- ccxt/async_support/defx.py +2066 -0
- ccxt/async_support/delta.py +404 -109
- ccxt/async_support/deribit.py +639 -323
- ccxt/async_support/digifinex.py +465 -233
- ccxt/async_support/ellipx.py +1887 -0
- ccxt/async_support/exmo.py +317 -128
- ccxt/async_support/gate.py +1472 -463
- ccxt/async_support/gemini.py +206 -84
- ccxt/async_support/hashkey.py +4164 -0
- ccxt/async_support/hitbtc.py +433 -178
- ccxt/async_support/hollaex.py +207 -83
- ccxt/async_support/htx.py +1095 -563
- ccxt/async_support/huobijp.py +178 -56
- ccxt/async_support/hyperliquid.py +1678 -292
- ccxt/async_support/idex.py +219 -95
- ccxt/async_support/independentreserve.py +300 -31
- ccxt/async_support/indodax.py +226 -62
- ccxt/async_support/kraken.py +871 -354
- ccxt/async_support/krakenfutures.py +324 -100
- ccxt/async_support/kucoin.py +917 -357
- ccxt/async_support/kucoinfutures.py +1004 -149
- ccxt/async_support/kuna.py +198 -107
- ccxt/async_support/latoken.py +199 -79
- ccxt/async_support/lbank.py +360 -113
- ccxt/async_support/luno.py +185 -62
- ccxt/async_support/lykke.py +168 -55
- ccxt/async_support/mercado.py +101 -29
- ccxt/async_support/mexc.py +995 -429
- ccxt/async_support/myokx.py +53 -0
- ccxt/async_support/ndax.py +234 -82
- ccxt/async_support/novadax.py +195 -75
- ccxt/async_support/oceanex.py +244 -59
- ccxt/async_support/okcoin.py +301 -165
- ccxt/async_support/okx.py +1776 -454
- ccxt/async_support/onetrading.py +198 -414
- ccxt/async_support/oxfun.py +2898 -0
- ccxt/async_support/p2b.py +142 -52
- ccxt/async_support/paradex.py +2085 -0
- ccxt/async_support/paymium.py +56 -32
- ccxt/async_support/phemex.py +572 -196
- ccxt/async_support/poloniex.py +218 -95
- ccxt/async_support/poloniexfutures.py +260 -92
- ccxt/async_support/probit.py +143 -110
- ccxt/async_support/timex.py +123 -70
- ccxt/async_support/tokocrypto.py +129 -93
- ccxt/async_support/tradeogre.py +39 -25
- ccxt/async_support/upbit.py +322 -113
- ccxt/async_support/vertex.py +2983 -0
- ccxt/async_support/wavesexchange.py +227 -173
- ccxt/async_support/wazirx.py +145 -65
- ccxt/async_support/whitebit.py +533 -138
- ccxt/async_support/woo.py +1137 -296
- ccxt/async_support/woofipro.py +2716 -0
- ccxt/async_support/xt.py +4628 -0
- ccxt/async_support/yobit.py +160 -92
- ccxt/async_support/zaif.py +80 -33
- ccxt/async_support/zonda.py +140 -69
- ccxt/base/errors.py +51 -20
- ccxt/base/exchange.py +1722 -480
- ccxt/base/precise.py +10 -0
- ccxt/base/types.py +223 -4
- ccxt/bequant.py +1 -1
- ccxt/bigone.py +329 -202
- ccxt/binance.py +3030 -1087
- ccxt/binancecoinm.py +2 -1
- ccxt/binanceus.py +12 -1
- ccxt/binanceusdm.py +3 -1
- ccxt/bingx.py +3205 -937
- ccxt/bit2c.py +119 -38
- ccxt/bitbank.py +215 -76
- ccxt/bitbns.py +124 -53
- ccxt/bitfinex.py +3235 -1078
- ccxt/bitfinex1.py +1710 -0
- ccxt/bitflyer.py +238 -49
- ccxt/bitget.py +1525 -573
- ccxt/bithumb.py +198 -65
- ccxt/bitmart.py +1320 -435
- ccxt/bitmex.py +308 -111
- ccxt/bitopro.py +256 -96
- ccxt/bitrue.py +365 -233
- ccxt/bitso.py +201 -89
- ccxt/bitstamp.py +438 -269
- ccxt/bitteam.py +179 -73
- ccxt/bitvavo.py +180 -70
- ccxt/bl3p.py +92 -25
- ccxt/blockchaincom.py +193 -79
- ccxt/blofin.py +392 -148
- ccxt/btcalpha.py +161 -55
- ccxt/btcbox.py +250 -34
- ccxt/btcmarkets.py +232 -85
- ccxt/btcturk.py +159 -60
- ccxt/bybit.py +2231 -1193
- ccxt/cex.py +1408 -1329
- ccxt/coinbase.py +1454 -287
- ccxt/coinbaseadvanced.py +17 -0
- ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
- ccxt/coinbaseinternational.py +428 -88
- ccxt/coincatch.py +5152 -0
- ccxt/coincheck.py +121 -38
- ccxt/coinex.py +4020 -3339
- ccxt/coinlist.py +273 -116
- ccxt/coinmate.py +204 -97
- ccxt/coinmetro.py +203 -110
- ccxt/coinone.py +142 -68
- ccxt/coinsph.py +223 -97
- ccxt/coinspot.py +137 -62
- ccxt/cryptocom.py +515 -185
- ccxt/currencycom.py +203 -85
- ccxt/defx.py +2065 -0
- ccxt/delta.py +404 -109
- ccxt/deribit.py +639 -323
- ccxt/digifinex.py +465 -233
- ccxt/ellipx.py +1887 -0
- ccxt/exmo.py +317 -128
- ccxt/gate.py +1472 -463
- ccxt/gemini.py +206 -84
- ccxt/hashkey.py +4164 -0
- ccxt/hitbtc.py +433 -178
- ccxt/hollaex.py +207 -83
- ccxt/htx.py +1095 -563
- ccxt/huobijp.py +178 -56
- ccxt/hyperliquid.py +1677 -292
- ccxt/idex.py +219 -95
- ccxt/independentreserve.py +299 -31
- ccxt/indodax.py +226 -62
- ccxt/kraken.py +871 -354
- ccxt/krakenfutures.py +324 -100
- ccxt/kucoin.py +917 -357
- ccxt/kucoinfutures.py +1004 -149
- ccxt/kuna.py +198 -107
- ccxt/latoken.py +199 -79
- ccxt/lbank.py +360 -113
- ccxt/luno.py +185 -62
- ccxt/lykke.py +168 -55
- ccxt/mercado.py +101 -29
- ccxt/mexc.py +994 -429
- ccxt/myokx.py +53 -0
- ccxt/ndax.py +234 -82
- ccxt/novadax.py +195 -75
- ccxt/oceanex.py +244 -59
- ccxt/okcoin.py +301 -165
- ccxt/okx.py +1776 -454
- ccxt/onetrading.py +198 -414
- ccxt/oxfun.py +2897 -0
- ccxt/p2b.py +142 -52
- ccxt/paradex.py +2085 -0
- ccxt/paymium.py +56 -32
- ccxt/phemex.py +572 -196
- ccxt/poloniex.py +218 -95
- ccxt/poloniexfutures.py +260 -92
- ccxt/pro/__init__.py +29 -5
- ccxt/pro/alpaca.py +32 -17
- ccxt/pro/ascendex.py +62 -14
- ccxt/pro/bequant.py +4 -0
- ccxt/pro/binance.py +1596 -329
- ccxt/pro/binancecoinm.py +1 -0
- ccxt/pro/binanceus.py +2 -9
- ccxt/pro/binanceusdm.py +2 -0
- ccxt/pro/bingx.py +527 -134
- ccxt/pro/bitcoincom.py +4 -1
- ccxt/pro/bitfinex.py +731 -266
- ccxt/pro/bitfinex1.py +635 -0
- ccxt/pro/bitget.py +726 -357
- ccxt/pro/bithumb.py +380 -0
- ccxt/pro/bitmart.py +143 -39
- ccxt/pro/bitmex.py +199 -40
- ccxt/pro/bitopro.py +25 -13
- ccxt/pro/bitrue.py +31 -32
- ccxt/pro/bitstamp.py +7 -6
- ccxt/pro/bitvavo.py +203 -81
- ccxt/pro/blockchaincom.py +30 -17
- ccxt/pro/blofin.py +692 -0
- ccxt/pro/bybit.py +791 -82
- ccxt/pro/cex.py +99 -51
- ccxt/pro/coinbase.py +220 -30
- ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
- ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
- ccxt/pro/coinbaseinternational.py +193 -30
- ccxt/pro/coincatch.py +1464 -0
- ccxt/pro/coincheck.py +11 -6
- ccxt/pro/coinex.py +965 -665
- ccxt/pro/coinone.py +17 -10
- ccxt/pro/cryptocom.py +446 -66
- ccxt/pro/currencycom.py +11 -10
- ccxt/pro/defx.py +832 -0
- ccxt/pro/deribit.py +167 -31
- ccxt/pro/exmo.py +252 -20
- ccxt/pro/gate.py +729 -64
- ccxt/pro/gemini.py +44 -26
- ccxt/pro/hashkey.py +802 -0
- ccxt/pro/hitbtc.py +208 -103
- ccxt/pro/hollaex.py +25 -9
- ccxt/pro/htx.py +83 -39
- ccxt/pro/huobijp.py +17 -16
- ccxt/pro/hyperliquid.py +502 -31
- ccxt/pro/idex.py +28 -13
- ccxt/pro/independentreserve.py +21 -16
- ccxt/pro/kraken.py +298 -51
- ccxt/pro/krakenfutures.py +166 -75
- ccxt/pro/kucoin.py +395 -77
- ccxt/pro/kucoinfutures.py +400 -99
- ccxt/pro/lbank.py +52 -31
- ccxt/pro/luno.py +12 -10
- ccxt/pro/mexc.py +400 -50
- ccxt/pro/myokx.py +28 -0
- ccxt/pro/ndax.py +25 -12
- ccxt/pro/okcoin.py +28 -9
- ccxt/pro/okx.py +935 -124
- ccxt/pro/onetrading.py +41 -24
- ccxt/pro/oxfun.py +1054 -0
- ccxt/pro/p2b.py +100 -24
- ccxt/pro/paradex.py +352 -0
- ccxt/pro/phemex.py +92 -33
- ccxt/pro/poloniex.py +128 -49
- ccxt/pro/poloniexfutures.py +53 -32
- ccxt/pro/probit.py +92 -85
- ccxt/pro/upbit.py +401 -8
- ccxt/pro/vertex.py +943 -0
- ccxt/pro/wazirx.py +46 -28
- ccxt/pro/whitebit.py +65 -12
- ccxt/pro/woo.py +437 -65
- ccxt/pro/woofipro.py +1271 -0
- ccxt/pro/xt.py +1067 -0
- ccxt/probit.py +143 -110
- ccxt/static_dependencies/__init__.py +1 -1
- ccxt/static_dependencies/lark/__init__.py +38 -0
- ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
- ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
- ccxt/static_dependencies/lark/ast_utils.py +59 -0
- ccxt/static_dependencies/lark/common.py +86 -0
- ccxt/static_dependencies/lark/exceptions.py +292 -0
- ccxt/static_dependencies/lark/grammar.py +130 -0
- ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- ccxt/static_dependencies/lark/indenter.py +143 -0
- ccxt/static_dependencies/lark/lark.py +658 -0
- ccxt/static_dependencies/lark/lexer.py +678 -0
- ccxt/static_dependencies/lark/load_grammar.py +1428 -0
- ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
- ccxt/static_dependencies/lark/parser_frontends.py +257 -0
- ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
- ccxt/static_dependencies/lark/parsers/earley.py +314 -0
- ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
- ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
- ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
- ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
- ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
- ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
- ccxt/static_dependencies/lark/py.typed +0 -0
- ccxt/static_dependencies/lark/reconstruct.py +107 -0
- ccxt/static_dependencies/lark/tools/__init__.py +70 -0
- ccxt/static_dependencies/lark/tools/nearley.py +202 -0
- ccxt/static_dependencies/lark/tools/serialize.py +32 -0
- ccxt/static_dependencies/lark/tools/standalone.py +196 -0
- ccxt/static_dependencies/lark/tree.py +267 -0
- ccxt/static_dependencies/lark/tree_matcher.py +186 -0
- ccxt/static_dependencies/lark/tree_templates.py +180 -0
- ccxt/static_dependencies/lark/utils.py +343 -0
- ccxt/static_dependencies/lark/visitors.py +596 -0
- ccxt/static_dependencies/marshmallow/__init__.py +81 -0
- ccxt/static_dependencies/marshmallow/base.py +65 -0
- ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
- ccxt/static_dependencies/marshmallow/decorators.py +231 -0
- ccxt/static_dependencies/marshmallow/error_store.py +60 -0
- ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
- ccxt/static_dependencies/marshmallow/fields.py +2114 -0
- ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
- ccxt/static_dependencies/marshmallow/py.typed +0 -0
- ccxt/static_dependencies/marshmallow/schema.py +1228 -0
- ccxt/static_dependencies/marshmallow/types.py +12 -0
- ccxt/static_dependencies/marshmallow/utils.py +378 -0
- ccxt/static_dependencies/marshmallow/validate.py +678 -0
- ccxt/static_dependencies/marshmallow/warnings.py +2 -0
- ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
- ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
- ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
- ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
- ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
- ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
- ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
- ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
- ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- ccxt/static_dependencies/starknet/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
- ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
- ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
- ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
- ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
- ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
- ccxt/static_dependencies/starknet/common.py +15 -0
- ccxt/static_dependencies/starknet/constants.py +39 -0
- ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- ccxt/static_dependencies/starknet/hash/address.py +79 -0
- ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
- ccxt/static_dependencies/starknet/hash/selector.py +16 -0
- ccxt/static_dependencies/starknet/hash/storage.py +12 -0
- ccxt/static_dependencies/starknet/hash/utils.py +78 -0
- ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
- ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
- ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
- ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
- ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
- ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
- ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
- ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
- ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
- ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
- ccxt/static_dependencies/starknet/utils/schema.py +13 -0
- ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
- ccxt/static_dependencies/starkware/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
- ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
- ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
- ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
- ccxt/static_dependencies/sympy/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
- ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
- ccxt/static_dependencies/sympy/external/importtools.py +187 -0
- ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
- ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
- ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- ccxt/test/{test_async.py → tests_async.py} +456 -391
- ccxt/test/tests_helpers.py +285 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/{test_sync.py → tests_sync.py} +456 -393
- ccxt/timex.py +123 -70
- ccxt/tokocrypto.py +129 -93
- ccxt/tradeogre.py +39 -25
- ccxt/upbit.py +322 -113
- ccxt/vertex.py +2983 -0
- ccxt/wavesexchange.py +227 -173
- ccxt/wazirx.py +145 -65
- ccxt/whitebit.py +533 -138
- ccxt/woo.py +1137 -296
- ccxt/woofipro.py +2716 -0
- ccxt/xt.py +4627 -0
- ccxt/yobit.py +159 -92
- ccxt/zaif.py +80 -33
- ccxt/zonda.py +140 -69
- ccxt-4.4.49.dist-info/LICENSE.txt +21 -0
- ccxt-4.4.49.dist-info/METADATA +646 -0
- ccxt-4.4.49.dist-info/RECORD +669 -0
- {ccxt-4.2.77.dist-info → ccxt-4.4.49.dist-info}/WHEEL +1 -1
- ccxt/abstract/bitbay.py +0 -47
- ccxt/abstract/bitfinex2.py +0 -139
- ccxt/abstract/hitbtc3.py +0 -115
- ccxt/async_support/bitbay.py +0 -17
- ccxt/async_support/bitfinex2.py +0 -3496
- ccxt/async_support/flowbtc.py +0 -34
- ccxt/bitbay.py +0 -17
- ccxt/bitfinex2.py +0 -3496
- ccxt/flowbtc.py +0 -34
- ccxt/hitbtc3.py +0 -16
- ccxt/pro/bitfinex2.py +0 -1081
- ccxt/test/base/__init__.py +0 -28
- ccxt/test/base/test_account.py +0 -26
- ccxt/test/base/test_balance.py +0 -56
- ccxt/test/base/test_borrow_interest.py +0 -35
- ccxt/test/base/test_borrow_rate.py +0 -32
- ccxt/test/base/test_calculate_fee.py +0 -51
- ccxt/test/base/test_crypto.py +0 -127
- ccxt/test/base/test_currency.py +0 -76
- ccxt/test/base/test_datetime.py +0 -103
- ccxt/test/base/test_decimal_to_precision.py +0 -392
- ccxt/test/base/test_deep_extend.py +0 -68
- ccxt/test/base/test_deposit_withdrawal.py +0 -50
- ccxt/test/base/test_exchange_datetime_functions.py +0 -76
- ccxt/test/base/test_funding_rate_history.py +0 -29
- ccxt/test/base/test_last_price.py +0 -32
- ccxt/test/base/test_ledger_entry.py +0 -45
- ccxt/test/base/test_ledger_item.py +0 -48
- ccxt/test/base/test_leverage_tier.py +0 -33
- ccxt/test/base/test_margin_mode.py +0 -24
- ccxt/test/base/test_margin_modification.py +0 -35
- ccxt/test/base/test_market.py +0 -190
- ccxt/test/base/test_number.py +0 -411
- ccxt/test/base/test_ohlcv.py +0 -32
- ccxt/test/base/test_open_interest.py +0 -32
- ccxt/test/base/test_order.py +0 -64
- ccxt/test/base/test_order_book.py +0 -63
- ccxt/test/base/test_position.py +0 -60
- ccxt/test/base/test_shared_methods.py +0 -345
- ccxt/test/base/test_status.py +0 -24
- ccxt/test/base/test_throttle.py +0 -126
- ccxt/test/base/test_ticker.py +0 -86
- ccxt/test/base/test_trade.py +0 -47
- ccxt/test/base/test_trading_fee.py +0 -26
- ccxt/test/base/test_transaction.py +0 -39
- ccxt-4.2.77.dist-info/METADATA +0 -626
- ccxt-4.2.77.dist-info/RECORD +0 -534
- {ccxt-4.2.77.dist-info → ccxt-4.4.49.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
# File is copied from
|
2
|
+
# https://github.com/starkware-libs/cairo-lang/blob/v0.13.1/src/starkware/starknet/core/os/contract_class/compiled_class_hash_objects.py
|
3
|
+
|
4
|
+
import dataclasses
|
5
|
+
import itertools
|
6
|
+
from abc import ABC, abstractmethod
|
7
|
+
from typing import Any, List, Union
|
8
|
+
|
9
|
+
from poseidon_py.poseidon_hash import poseidon_hash_many
|
10
|
+
|
11
|
+
|
12
|
+
class BytecodeSegmentStructure(ABC):
|
13
|
+
"""
|
14
|
+
Represents the structure of the bytecode to allow loading it partially into the OS memory.
|
15
|
+
See the documentation of the OS function `bytecode_hash_node` in `compiled_class.cairo`
|
16
|
+
for more details.
|
17
|
+
"""
|
18
|
+
|
19
|
+
@abstractmethod
|
20
|
+
def hash(self) -> int:
|
21
|
+
"""
|
22
|
+
Computes the hash of the node.
|
23
|
+
"""
|
24
|
+
|
25
|
+
def bytecode_with_skipped_segments(self):
|
26
|
+
"""
|
27
|
+
Returns the bytecode of the node.
|
28
|
+
Skipped segments are replaced with [-1, -2, -2, -2, ...].
|
29
|
+
"""
|
30
|
+
res: List[int] = []
|
31
|
+
self.add_bytecode_with_skipped_segments(res)
|
32
|
+
return res
|
33
|
+
|
34
|
+
@abstractmethod
|
35
|
+
def add_bytecode_with_skipped_segments(self, data: List[int]):
|
36
|
+
"""
|
37
|
+
Same as bytecode_with_skipped_segments, but appends the result to the given list.
|
38
|
+
"""
|
39
|
+
|
40
|
+
|
41
|
+
@dataclasses.dataclass
|
42
|
+
class BytecodeLeaf(BytecodeSegmentStructure):
|
43
|
+
"""
|
44
|
+
Represents a leaf in the bytecode segment tree.
|
45
|
+
"""
|
46
|
+
|
47
|
+
data: List[int]
|
48
|
+
|
49
|
+
def hash(self) -> int:
|
50
|
+
return poseidon_hash_many(self.data)
|
51
|
+
|
52
|
+
def add_bytecode_with_skipped_segments(self, data: List[int]):
|
53
|
+
data.extend(self.data)
|
54
|
+
|
55
|
+
|
56
|
+
@dataclasses.dataclass
|
57
|
+
class BytecodeSegmentedNode(BytecodeSegmentStructure):
|
58
|
+
"""
|
59
|
+
Represents an internal node in the bytecode segment tree.
|
60
|
+
Each child can be loaded into memory or skipped.
|
61
|
+
"""
|
62
|
+
|
63
|
+
segments: List["BytecodeSegment"]
|
64
|
+
|
65
|
+
def hash(self) -> int:
|
66
|
+
return (
|
67
|
+
poseidon_hash_many(
|
68
|
+
itertools.chain( # pyright: ignore
|
69
|
+
*[
|
70
|
+
(node.segment_length, node.inner_structure.hash())
|
71
|
+
for node in self.segments
|
72
|
+
]
|
73
|
+
)
|
74
|
+
)
|
75
|
+
+ 1
|
76
|
+
)
|
77
|
+
|
78
|
+
def add_bytecode_with_skipped_segments(self, data: List[int]):
|
79
|
+
for segment in self.segments:
|
80
|
+
if segment.is_used:
|
81
|
+
segment.inner_structure.add_bytecode_with_skipped_segments(data)
|
82
|
+
else:
|
83
|
+
data.append(-1)
|
84
|
+
data.extend(-2 for _ in range(segment.segment_length - 1))
|
85
|
+
|
86
|
+
|
87
|
+
@dataclasses.dataclass
|
88
|
+
class BytecodeSegment:
|
89
|
+
"""
|
90
|
+
Represents a child of BytecodeSegmentedNode.
|
91
|
+
"""
|
92
|
+
|
93
|
+
# The length of the segment.
|
94
|
+
segment_length: int
|
95
|
+
# Should the segment (or part of it) be loaded to memory.
|
96
|
+
# In other words, is the segment used during the execution.
|
97
|
+
# Note that if is_used is False, the entire segment is not loaded to memory.
|
98
|
+
# If is_used is True, it is possible that part of the segment will be skipped (according
|
99
|
+
# to the "is_used" field of the child segments).
|
100
|
+
is_used: bool
|
101
|
+
# The inner structure of the segment.
|
102
|
+
inner_structure: BytecodeSegmentStructure
|
103
|
+
|
104
|
+
def __post_init__(self):
|
105
|
+
assert (
|
106
|
+
self.segment_length > 0
|
107
|
+
), f"Invalid segment length: {self.segment_length}."
|
108
|
+
|
109
|
+
|
110
|
+
# Represents a nested list of integers. E.g., [1, [2, [3], 4], 5, 6].
|
111
|
+
NestedIntList = Union[int, List[Any]]
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from ..constants import (
|
2
|
+
DEFAULT_ENTRY_POINT_NAME,
|
3
|
+
DEFAULT_ENTRY_POINT_SELECTOR,
|
4
|
+
DEFAULT_L1_ENTRY_POINT_NAME,
|
5
|
+
)
|
6
|
+
from ..hash.utils import _starknet_keccak
|
7
|
+
|
8
|
+
|
9
|
+
def get_selector_from_name(func_name: str) -> int:
|
10
|
+
"""
|
11
|
+
Returns the selector of a contract's function name.
|
12
|
+
"""
|
13
|
+
if func_name in [DEFAULT_ENTRY_POINT_NAME, DEFAULT_L1_ENTRY_POINT_NAME]:
|
14
|
+
return DEFAULT_ENTRY_POINT_SELECTOR
|
15
|
+
|
16
|
+
return _starknet_keccak(data=func_name.encode("ascii"))
|
@@ -0,0 +1,12 @@
|
|
1
|
+
from functools import reduce
|
2
|
+
|
3
|
+
from constants import ADDR_BOUND
|
4
|
+
from hash.utils import _starknet_keccak, pedersen_hash
|
5
|
+
|
6
|
+
|
7
|
+
def get_storage_var_address(var_name: str, *args: int) -> int:
|
8
|
+
"""
|
9
|
+
Returns the storage address of a Starknet storage variable given its name and arguments.
|
10
|
+
"""
|
11
|
+
res = _starknet_keccak(var_name.encode("ascii"))
|
12
|
+
return reduce(pedersen_hash, args, res) % ADDR_BOUND
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import functools
|
2
|
+
from typing import List, Optional, Sequence
|
3
|
+
|
4
|
+
from ... import keccak
|
5
|
+
|
6
|
+
from ..common import int_from_bytes
|
7
|
+
from ..constants import EC_ORDER
|
8
|
+
from ...starkware.crypto.signature import (
|
9
|
+
ECSignature,
|
10
|
+
private_to_stark_key,
|
11
|
+
sign
|
12
|
+
# verify
|
13
|
+
)
|
14
|
+
from ...starkware.crypto.fast_pedersen_hash import (
|
15
|
+
pedersen_hash
|
16
|
+
)
|
17
|
+
|
18
|
+
MASK_250 = 2**250 - 1
|
19
|
+
HEX_PREFIX = "0x"
|
20
|
+
|
21
|
+
|
22
|
+
def _starknet_keccak(data: bytes) -> int:
|
23
|
+
"""
|
24
|
+
A variant of eth-keccak that computes a value that fits in a Starknet field element.
|
25
|
+
"""
|
26
|
+
return int_from_bytes(keccak.SHA3(data)) & MASK_250
|
27
|
+
|
28
|
+
|
29
|
+
# def pedersen_hash(left: int, right: int) -> int:
|
30
|
+
# """
|
31
|
+
# One of two hash functions (along with _starknet_keccak) used throughout Starknet.
|
32
|
+
# """
|
33
|
+
# return cpp_hash(left, right)
|
34
|
+
|
35
|
+
|
36
|
+
def compute_hash_on_elements(data: Sequence) -> int:
|
37
|
+
"""
|
38
|
+
Computes a hash chain over the data, in the following order:
|
39
|
+
h(h(h(h(0, data[0]), data[1]), ...), data[n-1]), n).
|
40
|
+
|
41
|
+
The hash is initialized with 0 and ends with the data length appended.
|
42
|
+
The length is appended in order to avoid collisions of the following kind:
|
43
|
+
H([x,y,z]) = h(h(x,y),z) = H([w, z]) where w = h(x,y).
|
44
|
+
"""
|
45
|
+
return functools.reduce(pedersen_hash, [*data, len(data)], 0)
|
46
|
+
|
47
|
+
|
48
|
+
def message_signature(
|
49
|
+
msg_hash: int, priv_key: int, seed: Optional[int] = 32
|
50
|
+
) -> ECSignature:
|
51
|
+
"""
|
52
|
+
Signs the message with private key.
|
53
|
+
"""
|
54
|
+
return sign(msg_hash, priv_key, seed)
|
55
|
+
|
56
|
+
|
57
|
+
# def verify_message_signature(
|
58
|
+
# msg_hash: int, signature: List[int], public_key: int
|
59
|
+
# ) -> bool:
|
60
|
+
# """
|
61
|
+
# Verifies ECDSA signature of a given message hash with a given public key.
|
62
|
+
# Returns true if public_key signs the message.
|
63
|
+
# """
|
64
|
+
# sig_r, sig_s = signature
|
65
|
+
# # sig_w = pow(sig_s, -1, EC_ORDER)
|
66
|
+
# return verify(msg_hash=msg_hash, r=sig_r, s=sig_s, public_key=public_key)
|
67
|
+
|
68
|
+
|
69
|
+
def encode_uint(value: int, bytes_length: int = 32) -> bytes:
|
70
|
+
return value.to_bytes(bytes_length, byteorder="big")
|
71
|
+
|
72
|
+
|
73
|
+
def encode_uint_list(data: List[int]) -> bytes:
|
74
|
+
return b"".join(encode_uint(x) for x in data)
|
75
|
+
|
76
|
+
|
77
|
+
def get_bytes_length(value: int) -> int:
|
78
|
+
return (value.bit_length() + 7) // 8
|
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
"""
|
2
|
+
TypedDict structures for TypedData
|
3
|
+
"""
|
4
|
+
|
5
|
+
from enum import Enum
|
6
|
+
from typing import Any, Dict, List, Optional, TypedDict
|
7
|
+
|
8
|
+
class Revision(Enum):
|
9
|
+
"""
|
10
|
+
Enum representing the revision of the specification to be used.
|
11
|
+
"""
|
12
|
+
|
13
|
+
V0 = 0
|
14
|
+
V1 = 1
|
15
|
+
|
16
|
+
|
17
|
+
class ParameterDict(TypedDict):
|
18
|
+
"""
|
19
|
+
TypedDict representing a Parameter object
|
20
|
+
"""
|
21
|
+
|
22
|
+
name: str
|
23
|
+
type: str
|
24
|
+
|
25
|
+
|
26
|
+
class StarkNetDomainDict(TypedDict):
|
27
|
+
"""
|
28
|
+
TypedDict representing a domain object (both StarkNetDomain, StarknetDomain).
|
29
|
+
"""
|
30
|
+
|
31
|
+
name: str
|
32
|
+
version: str
|
33
|
+
chainId: str
|
34
|
+
revision: Optional[Revision]
|
35
|
+
|
36
|
+
|
37
|
+
class TypedDataDict(TypedDict):
|
38
|
+
"""
|
39
|
+
TypedDict representing a TypedData object
|
40
|
+
"""
|
41
|
+
|
42
|
+
types: Dict[str, List[ParameterDict]]
|
43
|
+
primaryType: str
|
44
|
+
domain: StarkNetDomainDict
|
45
|
+
message: Dict[str, Any]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# PayloadSerializer and FunctionSerializationAdapter would mostly be used by users
|
2
|
+
from .data_serializers import (
|
3
|
+
ArraySerializer,
|
4
|
+
CairoDataSerializer,
|
5
|
+
FeltSerializer,
|
6
|
+
NamedTupleSerializer,
|
7
|
+
PayloadSerializer,
|
8
|
+
StructSerializer,
|
9
|
+
TupleSerializer,
|
10
|
+
Uint256Serializer,
|
11
|
+
)
|
12
|
+
from .errors import (
|
13
|
+
CairoSerializerException,
|
14
|
+
InvalidTypeException,
|
15
|
+
InvalidValueException,
|
16
|
+
)
|
17
|
+
from .factory import (
|
18
|
+
serializer_for_event,
|
19
|
+
serializer_for_function,
|
20
|
+
serializer_for_payload,
|
21
|
+
serializer_for_type,
|
22
|
+
)
|
23
|
+
from .function_serialization_adapter import FunctionSerializationAdapter
|
24
|
+
from .tuple_dataclass import TupleDataclass
|
@@ -0,0 +1,40 @@
|
|
1
|
+
from typing import List
|
2
|
+
|
3
|
+
from ..cairo.felt import CairoData
|
4
|
+
|
5
|
+
|
6
|
+
class OutOfBoundsError(Exception):
|
7
|
+
def __init__(self, position: int, requested_size: int, remaining_size: int):
|
8
|
+
super().__init__(
|
9
|
+
f"Requested {requested_size} elements, {remaining_size} available."
|
10
|
+
)
|
11
|
+
self.position = position
|
12
|
+
self.requested_size = requested_size
|
13
|
+
self.remaining_len = remaining_size
|
14
|
+
|
15
|
+
|
16
|
+
class CalldataReader:
|
17
|
+
_data: List[int]
|
18
|
+
_position: int
|
19
|
+
|
20
|
+
def __init__(self, data: List[int]):
|
21
|
+
self._data = data
|
22
|
+
self._position = 0
|
23
|
+
|
24
|
+
@property
|
25
|
+
def remaining_len(self) -> int:
|
26
|
+
return len(self._data) - self._position
|
27
|
+
|
28
|
+
def read(self, size: int) -> CairoData:
|
29
|
+
if size < 1:
|
30
|
+
raise ValueError("size must be greater than 0")
|
31
|
+
|
32
|
+
if size > self.remaining_len:
|
33
|
+
raise OutOfBoundsError(
|
34
|
+
position=self._position,
|
35
|
+
requested_size=size,
|
36
|
+
remaining_size=self.remaining_len,
|
37
|
+
)
|
38
|
+
data = self._data[self._position : self._position + size]
|
39
|
+
self._position += size
|
40
|
+
return data
|
@@ -0,0 +1,142 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from abc import ABC
|
4
|
+
from contextlib import contextmanager
|
5
|
+
from typing import Any, Generator, Iterator, List
|
6
|
+
|
7
|
+
from ._calldata_reader import (
|
8
|
+
CairoData,
|
9
|
+
CalldataReader,
|
10
|
+
OutOfBoundsError,
|
11
|
+
)
|
12
|
+
from .errors import InvalidTypeException, InvalidValueException
|
13
|
+
|
14
|
+
|
15
|
+
class Context(ABC):
|
16
|
+
"""
|
17
|
+
Holds information about context when (de)serializing data. This is needed to inform what and where went
|
18
|
+
wrong during processing. Every separate (de)serialization should have its own context.
|
19
|
+
"""
|
20
|
+
|
21
|
+
_namespace_stack: List[str]
|
22
|
+
|
23
|
+
def __init__(self):
|
24
|
+
self._namespace_stack = []
|
25
|
+
|
26
|
+
@property
|
27
|
+
def current_entity(self):
|
28
|
+
"""
|
29
|
+
Name of currently processed entity.
|
30
|
+
|
31
|
+
:return: transformed path.
|
32
|
+
"""
|
33
|
+
return ".".join(self._namespace_stack)
|
34
|
+
|
35
|
+
@contextmanager
|
36
|
+
def push_entity(self, name: str) -> Generator:
|
37
|
+
"""
|
38
|
+
Manager used for maintaining information about names of (de)serialized types. Wraps some errors with
|
39
|
+
custom errors, adding information about the context.
|
40
|
+
|
41
|
+
:param name: name of (de)serialized entity.
|
42
|
+
"""
|
43
|
+
# This ensures the name will be popped if everything is ok. In case an exception is raised we want the stack to
|
44
|
+
# be filled to wrap the error at the end.
|
45
|
+
self._namespace_stack.append(name)
|
46
|
+
yield
|
47
|
+
self._namespace_stack.pop()
|
48
|
+
|
49
|
+
def ensure_valid_value(self, valid: bool, text: str):
|
50
|
+
if not valid:
|
51
|
+
raise InvalidValueException(f"{self._error_prefix}: {text}.")
|
52
|
+
|
53
|
+
def ensure_valid_type(self, value: Any, valid: bool, expected_type: str):
|
54
|
+
if not valid:
|
55
|
+
raise InvalidTypeException(
|
56
|
+
f"{self._error_prefix}: expected {expected_type}, "
|
57
|
+
f"received '{value}' of type '{type(value)}'."
|
58
|
+
)
|
59
|
+
|
60
|
+
@contextmanager
|
61
|
+
def _wrap_errors(self):
|
62
|
+
try:
|
63
|
+
yield
|
64
|
+
except OutOfBoundsError as err:
|
65
|
+
action_name = (
|
66
|
+
f"deserialize '{self.current_entity}'"
|
67
|
+
if self._namespace_stack
|
68
|
+
else "deserialize"
|
69
|
+
)
|
70
|
+
# This way we can precisely inform user what's wrong when reading calldata.
|
71
|
+
raise InvalidValueException(
|
72
|
+
f"Not enough data to {action_name}. "
|
73
|
+
f"Can't read {err.requested_size} values at position {err.position}, {err.remaining_len} available."
|
74
|
+
) from err
|
75
|
+
|
76
|
+
# Those two are based on ValueError and TypeError, we have to catch them early
|
77
|
+
except (InvalidValueException, InvalidTypeException) as err:
|
78
|
+
raise err
|
79
|
+
|
80
|
+
except ValueError as err:
|
81
|
+
raise InvalidValueException(f"{self._error_prefix}: {err}") from err
|
82
|
+
except TypeError as err:
|
83
|
+
raise InvalidTypeException(f"{self._error_prefix}: {err}") from err
|
84
|
+
|
85
|
+
@property
|
86
|
+
def _error_prefix(self):
|
87
|
+
if not self._namespace_stack:
|
88
|
+
return "Error"
|
89
|
+
return f"Error at path '{self.current_entity}'"
|
90
|
+
|
91
|
+
|
92
|
+
class SerializationContext(Context):
|
93
|
+
"""
|
94
|
+
Context used during serialization.
|
95
|
+
"""
|
96
|
+
|
97
|
+
# Type is iterator, because ContextManager doesn't work with pyright :|
|
98
|
+
# https://github.com/microsoft/pyright/issues/476
|
99
|
+
@classmethod
|
100
|
+
@contextmanager
|
101
|
+
def create(cls) -> Iterator[SerializationContext]:
|
102
|
+
context = cls()
|
103
|
+
with context._wrap_errors():
|
104
|
+
yield context
|
105
|
+
|
106
|
+
|
107
|
+
class DeserializationContext(Context):
|
108
|
+
"""
|
109
|
+
Context used during deserialization.
|
110
|
+
"""
|
111
|
+
|
112
|
+
reader: CalldataReader
|
113
|
+
|
114
|
+
def __init__(self, calldata: CairoData):
|
115
|
+
"""
|
116
|
+
Don't use default constructor. Use DeserializationContext.create context manager.
|
117
|
+
"""
|
118
|
+
super().__init__()
|
119
|
+
self._namespace_stack = []
|
120
|
+
self.reader = CalldataReader(calldata)
|
121
|
+
|
122
|
+
@classmethod
|
123
|
+
@contextmanager
|
124
|
+
def create(cls, data: CairoData) -> Iterator[DeserializationContext]:
|
125
|
+
context = cls(data)
|
126
|
+
with context._wrap_errors():
|
127
|
+
yield context
|
128
|
+
context._ensure_all_values_read(len(data))
|
129
|
+
|
130
|
+
def _ensure_all_values_read(self, total_len: int):
|
131
|
+
values_not_used = self.reader.remaining_len
|
132
|
+
if values_not_used != 0:
|
133
|
+
# We want to output up to 3 values. It there is more they will be truncated like "0x1,0x1,0x1..."
|
134
|
+
max_values_to_show = 3
|
135
|
+
values_to_show = min(values_not_used, max_values_to_show)
|
136
|
+
example = ",".join(hex(v) for v in self.reader.read(values_to_show))
|
137
|
+
suffix = "..." if values_not_used > max_values_to_show else ""
|
138
|
+
|
139
|
+
raise InvalidValueException(
|
140
|
+
f"Last {values_not_used} values '{example}{suffix}' out of total {total_len} "
|
141
|
+
"values were not used during deserialization."
|
142
|
+
)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
from .array_serializer import ArraySerializer
|
2
|
+
from .bool_serializer import BoolSerializer
|
3
|
+
from .byte_array_serializer import ByteArraySerializer
|
4
|
+
from .cairo_data_serializer import CairoDataSerializer
|
5
|
+
from .felt_serializer import FeltSerializer
|
6
|
+
from .named_tuple_serializer import NamedTupleSerializer
|
7
|
+
from .payload_serializer import PayloadSerializer
|
8
|
+
from .struct_serializer import StructSerializer
|
9
|
+
from .tuple_serializer import TupleSerializer
|
10
|
+
from .uint256_serializer import Uint256Serializer
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# We have to use parametrised type from typing
|
2
|
+
from collections import OrderedDict as _OrderedDict
|
3
|
+
from typing import Dict, Generator, List, OrderedDict
|
4
|
+
|
5
|
+
from .._context import (
|
6
|
+
DeserializationContext,
|
7
|
+
SerializationContext,
|
8
|
+
)
|
9
|
+
from .cairo_data_serializer import (
|
10
|
+
CairoDataSerializer,
|
11
|
+
)
|
12
|
+
|
13
|
+
# The actual serialization logic is very similar among all serializers: they either serialize data based on
|
14
|
+
# position or their name. Having this logic reused adds indirection, but makes sure proper logic is used everywhere.
|
15
|
+
|
16
|
+
|
17
|
+
def deserialize_to_list(
|
18
|
+
deserializers: List[CairoDataSerializer], context: DeserializationContext
|
19
|
+
) -> List:
|
20
|
+
"""
|
21
|
+
Deserializes data from context to list. This logic is used in every sequential type (arrays and tuples).
|
22
|
+
"""
|
23
|
+
result = []
|
24
|
+
|
25
|
+
for index, serializer in enumerate(deserializers):
|
26
|
+
with context.push_entity(f"[{index}]"):
|
27
|
+
result.append(serializer.deserialize_with_context(context))
|
28
|
+
|
29
|
+
return result
|
30
|
+
|
31
|
+
|
32
|
+
def deserialize_to_dict(
|
33
|
+
deserializers: OrderedDict[str, CairoDataSerializer],
|
34
|
+
context: DeserializationContext,
|
35
|
+
) -> OrderedDict:
|
36
|
+
"""
|
37
|
+
Deserializes data from context to dictionary. This logic is used in every type with named fields (structs,
|
38
|
+
named tuples and payloads).
|
39
|
+
"""
|
40
|
+
result = _OrderedDict()
|
41
|
+
|
42
|
+
for key, serializer in deserializers.items():
|
43
|
+
with context.push_entity(key):
|
44
|
+
result[key] = serializer.deserialize_with_context(context)
|
45
|
+
|
46
|
+
return result
|
47
|
+
|
48
|
+
|
49
|
+
def serialize_from_list(
|
50
|
+
serializers: List[CairoDataSerializer], context: SerializationContext, values: List
|
51
|
+
) -> Generator[int, None, None]:
|
52
|
+
"""
|
53
|
+
Serializes data from list. This logic is used in every sequential type (arrays and tuples).
|
54
|
+
"""
|
55
|
+
context.ensure_valid_value(
|
56
|
+
len(serializers) == len(values),
|
57
|
+
f"expected {len(serializers)} elements, {len(values)} provided",
|
58
|
+
)
|
59
|
+
|
60
|
+
for index, (serializer, value) in enumerate(zip(serializers, values)):
|
61
|
+
with context.push_entity(f"[{index}]"):
|
62
|
+
yield from serializer.serialize_with_context(context, value)
|
63
|
+
|
64
|
+
|
65
|
+
def serialize_from_dict(
|
66
|
+
serializers: OrderedDict[str, CairoDataSerializer],
|
67
|
+
context: SerializationContext,
|
68
|
+
values: Dict,
|
69
|
+
) -> Generator[int, None, None]:
|
70
|
+
"""
|
71
|
+
Serializes data from dict. This logic is used in every type with named fields (structs, named tuples and payloads).
|
72
|
+
"""
|
73
|
+
excessive_keys = set(values.keys()).difference(serializers.keys())
|
74
|
+
context.ensure_valid_value(
|
75
|
+
not excessive_keys,
|
76
|
+
f"unexpected keys '{','.join(excessive_keys)}' were provided",
|
77
|
+
)
|
78
|
+
|
79
|
+
for name, serializer in serializers.items():
|
80
|
+
with context.push_entity(name):
|
81
|
+
context.ensure_valid_value(name in values, f"key '{name}' is missing")
|
82
|
+
yield from serializer.serialize_with_context(context, values[name])
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import Generator, Iterable, List
|
3
|
+
|
4
|
+
from .._context import (
|
5
|
+
DeserializationContext,
|
6
|
+
SerializationContext,
|
7
|
+
)
|
8
|
+
from ..data_serializers._common import (
|
9
|
+
deserialize_to_list,
|
10
|
+
serialize_from_list,
|
11
|
+
)
|
12
|
+
from ..data_serializers.cairo_data_serializer import (
|
13
|
+
CairoDataSerializer,
|
14
|
+
)
|
15
|
+
|
16
|
+
|
17
|
+
@dataclass
|
18
|
+
class ArraySerializer(CairoDataSerializer[Iterable, List]):
|
19
|
+
"""
|
20
|
+
Serializer for arrays. In abi they are represented as a pointer to a type.
|
21
|
+
Can serialize any iterable and prepends its length to resulting list.
|
22
|
+
Deserializes data to a list.
|
23
|
+
|
24
|
+
Examples:
|
25
|
+
[1,2,3] => [3,1,2,3]
|
26
|
+
[] => [0]
|
27
|
+
"""
|
28
|
+
|
29
|
+
inner_serializer: CairoDataSerializer
|
30
|
+
|
31
|
+
def deserialize_with_context(self, context: DeserializationContext) -> List:
|
32
|
+
with context.push_entity("len"):
|
33
|
+
[size] = context.reader.read(1)
|
34
|
+
|
35
|
+
return deserialize_to_list([self.inner_serializer] * size, context)
|
36
|
+
|
37
|
+
def serialize_with_context(
|
38
|
+
self, context: SerializationContext, value: List
|
39
|
+
) -> Generator[int, None, None]:
|
40
|
+
yield len(value)
|
41
|
+
yield from serialize_from_list(
|
42
|
+
[self.inner_serializer] * len(value), context, value
|
43
|
+
)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import Generator
|
3
|
+
|
4
|
+
from .._context import (
|
5
|
+
Context,
|
6
|
+
DeserializationContext,
|
7
|
+
SerializationContext,
|
8
|
+
)
|
9
|
+
from .cairo_data_serializer import (
|
10
|
+
CairoDataSerializer,
|
11
|
+
)
|
12
|
+
|
13
|
+
|
14
|
+
@dataclass
|
15
|
+
class BoolSerializer(CairoDataSerializer[bool, int]):
|
16
|
+
"""
|
17
|
+
Serializer for boolean.
|
18
|
+
"""
|
19
|
+
|
20
|
+
def deserialize_with_context(self, context: DeserializationContext) -> bool:
|
21
|
+
[val] = context.reader.read(1)
|
22
|
+
self._ensure_bool(context, val)
|
23
|
+
return bool(val)
|
24
|
+
|
25
|
+
def serialize_with_context(
|
26
|
+
self, context: SerializationContext, value: bool
|
27
|
+
) -> Generator[int, None, None]:
|
28
|
+
context.ensure_valid_type(value, isinstance(value, bool), "bool")
|
29
|
+
self._ensure_bool(context, value)
|
30
|
+
yield int(value)
|
31
|
+
|
32
|
+
@staticmethod
|
33
|
+
def _ensure_bool(context: Context, value: int):
|
34
|
+
context.ensure_valid_value(
|
35
|
+
value in [0, 1],
|
36
|
+
f"invalid value '{value}' - must be in [0, 2) range",
|
37
|
+
)
|