genlayer 0.12.3 → 0.12.5

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.
Files changed (67) hide show
  1. package/.env.example +4 -0
  2. package/CHANGELOG.md +8 -0
  3. package/dist/index.js +409 -80
  4. package/esbuild.config.dev.js +1 -2
  5. package/esbuild.config.prod.js +1 -1
  6. package/eslint.config.js +2 -1
  7. package/package.json +5 -3
  8. package/src/commands/contracts/call.ts +16 -20
  9. package/src/commands/contracts/deploy.ts +107 -25
  10. package/src/commands/contracts/index.ts +14 -3
  11. package/src/commands/general/init.ts +0 -1
  12. package/src/commands/scaffold/index.ts +16 -0
  13. package/src/commands/scaffold/new.ts +34 -0
  14. package/src/index.ts +2 -0
  15. package/src/lib/actions/BaseAction.ts +11 -6
  16. package/src/lib/config/simulator.ts +2 -2
  17. package/templates/default/LICENSE +21 -0
  18. package/templates/default/README.md +101 -0
  19. package/templates/default/__init__.py +0 -0
  20. package/templates/default/app/.env.example +2 -0
  21. package/templates/default/app/.vscode/extensions.json +3 -0
  22. package/templates/default/app/README.md +5 -0
  23. package/templates/default/app/index.html +17 -0
  24. package/templates/default/app/package-lock.json +4920 -0
  25. package/templates/default/app/package.json +23 -0
  26. package/templates/default/app/postcss.config.js +6 -0
  27. package/templates/default/app/public/favicon.png +0 -0
  28. package/templates/default/app/src/App.vue +16 -0
  29. package/templates/default/app/src/components/Address.vue +38 -0
  30. package/templates/default/app/src/components/BetsScreen.vue +329 -0
  31. package/templates/default/app/src/logic/FootballBets.js +100 -0
  32. package/templates/default/app/src/main.js +5 -0
  33. package/templates/default/app/src/services/genlayer.js +19 -0
  34. package/templates/default/app/src/style.css +3 -0
  35. package/templates/default/app/tailwind.config.js +8 -0
  36. package/templates/default/app/vite.config.js +7 -0
  37. package/templates/default/config/__init__.py +0 -0
  38. package/templates/default/config/genlayer_config.py +14 -0
  39. package/templates/default/contracts/__init__.py +0 -0
  40. package/templates/default/contracts/football_bets.py +119 -0
  41. package/templates/default/deploy/deployScript.ts +31 -0
  42. package/templates/default/package-lock.json +3231 -0
  43. package/templates/default/package.json +7 -0
  44. package/templates/default/requirements.txt +6 -0
  45. package/templates/default/test/__init__.py +0 -0
  46. package/templates/default/test/football_bets_get_contract_schema_for_code.py +124 -0
  47. package/templates/default/test/test_football_bet_success_draw.py +108 -0
  48. package/templates/default/test/test_football_bet_success_win.py +106 -0
  49. package/templates/default/test/test_football_bet_unsuccess.py +107 -0
  50. package/templates/default/tools/__init__.py +0 -0
  51. package/templates/default/tools/accounts.py +5 -0
  52. package/templates/default/tools/calldata.py +224 -0
  53. package/templates/default/tools/request.py +134 -0
  54. package/templates/default/tools/response.py +52 -0
  55. package/templates/default/tools/structure.py +39 -0
  56. package/templates/default/tools/transactions.py +28 -0
  57. package/templates/default/tools/types.py +214 -0
  58. package/templates/default/tsconfig.json +7 -0
  59. package/tests/actions/call.test.ts +38 -76
  60. package/tests/actions/deploy.test.ts +200 -30
  61. package/tests/actions/new.test.ts +80 -0
  62. package/tests/commands/call.test.ts +6 -1
  63. package/tests/commands/deploy.test.ts +12 -1
  64. package/tests/commands/new.test.ts +68 -0
  65. package/tests/index.test.ts +4 -0
  66. package/tests/libs/baseAction.test.ts +17 -0
  67. package/vitest.config.ts +1 -1
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "genlayer-project",
3
+ "type": "module",
4
+ "devDependencies": {
5
+ "genlayer-js": "^0.6.0"
6
+ }
7
+ }
@@ -0,0 +1,6 @@
1
+ requests==2.31.0
2
+ python-dotenv==1.0.1
3
+ pytest==8.2.1
4
+ pytest-mock==3.14.0
5
+ eth-account==0.13.3
6
+ eth-utils==5.0.0
File without changes
@@ -0,0 +1,124 @@
1
+ football_bets_contract_schema = {
2
+ "id": 1,
3
+ "jsonrpc": "2.0",
4
+ "result": {
5
+ "ctor": {"kwparams": {}, "params": []},
6
+ "methods": {
7
+ "create_bet": {
8
+ "kwparams": {},
9
+ "params": [
10
+ ["game_date", "string"],
11
+ ["team1", "string"],
12
+ ["team2", "string"],
13
+ ["predicted_winner", "string"],
14
+ ],
15
+ "readonly": False,
16
+ "ret": "null",
17
+ },
18
+ "get_bets": {"kwparams": {}, "params": [], "readonly": True, "ret": "dict"},
19
+ "get_player_points": {
20
+ "kwparams": {},
21
+ "params": [["player_address", "string"]],
22
+ "readonly": True,
23
+ "ret": "int",
24
+ },
25
+ "get_points": {
26
+ "kwparams": {},
27
+ "params": [],
28
+ "readonly": True,
29
+ "ret": "dict",
30
+ },
31
+ "resolve_bet": {
32
+ "kwparams": {},
33
+ "params": [["bet_id", "string"]],
34
+ "readonly": False,
35
+ "ret": "null",
36
+ },
37
+ },
38
+ },
39
+ }
40
+
41
+
42
+ test_football_bets_win_unresolved = {
43
+ "2024-06-20_spain_italy": {
44
+ "game_date": "2024-06-20",
45
+ "has_resolved": False,
46
+ "id": "2024-06-20_spain_italy",
47
+ "predicted_winner": "1",
48
+ "real_score": None,
49
+ "real_winner": None,
50
+ "resolution_url": "https://www.bbc.com/sport/football/scores-fixtures/2024-06-20",
51
+ "team1": "Spain",
52
+ "team2": "Italy",
53
+ }
54
+ }
55
+
56
+ test_football_bets_win_resolved = {
57
+ "2024-06-20_spain_italy": {
58
+ "game_date": "2024-06-20",
59
+ "has_resolved": True,
60
+ "id": "2024-06-20_spain_italy",
61
+ "predicted_winner": "1",
62
+ "real_score": "1:0",
63
+ "real_winner": "1",
64
+ "resolution_url": "https://www.bbc.com/sport/football/scores-fixtures/2024-06-20",
65
+ "team1": "Spain",
66
+ "team2": "Italy",
67
+ }
68
+ }
69
+
70
+ test_football_bets_draw_unresolved = {
71
+ "2024-06-20_denmark_england": {
72
+ "game_date": "2024-06-20",
73
+ "has_resolved": False,
74
+ "id": "2024-06-20_denmark_england",
75
+ "predicted_winner": "0",
76
+ "real_score": None,
77
+ "real_winner": None,
78
+ "resolution_url": "https://www.bbc.com/sport/football/scores-fixtures/2024-06-20",
79
+ "team1": "Denmark",
80
+ "team2": "England",
81
+ }
82
+ }
83
+
84
+ test_football_bets_draw_resolved = {
85
+ "2024-06-20_denmark_england": {
86
+ "game_date": "2024-06-20",
87
+ "has_resolved": True,
88
+ "id": "2024-06-20_denmark_england",
89
+ "predicted_winner": "0",
90
+ "real_score": "1:1",
91
+ "real_winner": "0",
92
+ "resolution_url": "https://www.bbc.com/sport/football/scores-fixtures/2024-06-20",
93
+ "team1": "Denmark",
94
+ "team2": "England",
95
+ }
96
+ }
97
+
98
+ test_football_bets_unsuccess_unresolved = {
99
+ "2024-06-20_spain_italy": {
100
+ "game_date": "2024-06-20",
101
+ "has_resolved": False,
102
+ "id": "2024-06-20_spain_italy",
103
+ "predicted_winner": "2",
104
+ "real_score": None,
105
+ "real_winner": None,
106
+ "resolution_url": "https://www.bbc.com/sport/football/scores-fixtures/2024-06-20",
107
+ "team1": "Spain",
108
+ "team2": "Italy",
109
+ }
110
+ }
111
+
112
+ test_football_bets_unsuccess_resolved = {
113
+ "2024-06-20_spain_italy": {
114
+ "game_date": "2024-06-20",
115
+ "has_resolved": True,
116
+ "id": "2024-06-20_spain_italy",
117
+ "predicted_winner": "2",
118
+ "real_score": "1:0",
119
+ "real_winner": "1",
120
+ "resolution_url": "https://www.bbc.com/sport/football/scores-fixtures/2024-06-20",
121
+ "team1": "Spain",
122
+ "team2": "Italy",
123
+ }
124
+ }
@@ -0,0 +1,108 @@
1
+ # tests/e2e/test_wizard_of_coin.py
2
+
3
+ from tools.accounts import create_new_account
4
+ from tools.request import (
5
+ deploy_intelligent_contract,
6
+ send_transaction,
7
+ call_contract_method,
8
+ payload,
9
+ post_request,
10
+ )
11
+ from tools.structure import execute_icontract_function_response_structure
12
+ from tools.response import (
13
+ assert_dict_struct,
14
+ assert_dict_exact,
15
+ has_success_status,
16
+ )
17
+ from test.football_bets_get_contract_schema_for_code import (
18
+ football_bets_contract_schema,
19
+ test_football_bets_win_resolved,
20
+ test_football_bets_win_unresolved,
21
+ )
22
+
23
+
24
+ def test_football_bets_success():
25
+ # Account
26
+ account_1 = create_new_account()
27
+ # Validators - not needed for studio.genlayer.com
28
+ # result = post_request(
29
+ # payload("sim_createRandomValidators", 5, 8, 12, ["openai"], ["gpt-4o"])
30
+ # ).json()
31
+ # assert has_success_status(result)
32
+
33
+ # Contract Schema
34
+ contract_code = open("contracts/football_bets.py", "r").read()
35
+ result_schema = post_request(
36
+ payload("gen_getContractSchemaForCode", contract_code)
37
+ ).json()
38
+ assert has_success_status(result_schema)
39
+ assert_dict_exact(result_schema, football_bets_contract_schema)
40
+
41
+ # Contract Deploy
42
+ contract_address, transaction_response_deploy = deploy_intelligent_contract(
43
+ account_1,
44
+ contract_code,
45
+ "{}",
46
+ )
47
+ assert has_success_status(transaction_response_deploy)
48
+
49
+ # Get Initial State
50
+ contract_all_points_state = call_contract_method(
51
+ contract_address, account_1, "get_points", []
52
+ )
53
+ assert contract_all_points_state == {}
54
+
55
+ contract_all_bets_state = call_contract_method(
56
+ contract_address, account_1, "get_bets", []
57
+ )
58
+ assert contract_all_bets_state == {}
59
+
60
+ # Create Successful Bet
61
+ create_successful_bet_result = send_transaction(
62
+ account_1,
63
+ contract_address,
64
+ "create_bet",
65
+ ["2024-06-20", "Denmark", "England", "0"],
66
+ )
67
+ assert has_success_status(create_successful_bet_result)
68
+ assert_dict_struct(
69
+ create_successful_bet_result,
70
+ execute_icontract_function_response_structure,
71
+ )
72
+
73
+ # Get Bets
74
+ get_bet_result = call_contract_method(contract_address, account_1, "get_bets", [])
75
+ assert get_bet_result == {account_1.address: test_football_bets_win_unresolved}
76
+
77
+ # Resolve Successful Bet
78
+ resolve_successful_bet_result = send_transaction(
79
+ account_1,
80
+ contract_address,
81
+ "resolve_bet",
82
+ ["2024-06-20_denmark_england"],
83
+ )
84
+ assert has_success_status(resolve_successful_bet_result)
85
+ assert_dict_struct(
86
+ resolve_successful_bet_result,
87
+ execute_icontract_function_response_structure,
88
+ )
89
+
90
+ # Get Bets
91
+ get_bet_result = call_contract_method(contract_address, account_1, "get_bets", [])
92
+ assert get_bet_result == {account_1.address: test_football_bets_win_resolved}
93
+
94
+ # Get Points
95
+ get_points_result = call_contract_method(
96
+ contract_address, account_1, "get_points", []
97
+ )
98
+ assert get_points_result == {account_1.address: 1}
99
+
100
+ # Get Player Points
101
+ get_player_points_result = call_contract_method(
102
+ contract_address, account_1, "get_player_points", [account_1.address]
103
+ )
104
+ assert get_player_points_result == 1
105
+
106
+ # Delete Validators - not needed for studio.genlayer.com
107
+ # delete_validators_result = post_request(payload("sim_deleteAllValidators")).json()
108
+ # assert has_success_status(delete_validators_result)
@@ -0,0 +1,106 @@
1
+ # tests/e2e/test_wizard_of_coin.py
2
+
3
+ from tools.accounts import create_new_account
4
+ from tools.request import (
5
+ deploy_intelligent_contract,
6
+ send_transaction,
7
+ call_contract_method,
8
+ payload,
9
+ post_request,
10
+ )
11
+ from tools.structure import execute_icontract_function_response_structure
12
+ from tools.response import (
13
+ assert_dict_struct,
14
+ assert_dict_exact,
15
+ has_success_status,
16
+ )
17
+ from test.football_bets_get_contract_schema_for_code import (
18
+ football_bets_contract_schema,
19
+ test_football_bets_win_unresolved,
20
+ test_football_bets_win_resolved,
21
+ )
22
+
23
+
24
+ def test_football_bets_success():
25
+ # Account
26
+ account_1 = create_new_account()
27
+ # Validators - not needed for studio.genlayer.com
28
+ # result = post_request(
29
+ # payload("sim_createRandomValidators", 5, 8, 12, ["openai"], ["gpt-4o"])
30
+ # ).json()
31
+ # assert has_success_status(result)
32
+
33
+ # Contract Schema
34
+ contract_code = open("contracts/football_bet_market.py", "r").read()
35
+ result_schema = post_request(
36
+ payload("gen_getContractSchemaForCode", contract_code)
37
+ ).json()
38
+ assert has_success_status(result_schema)
39
+ assert_dict_exact(result_schema, football_bets_contract_schema)
40
+
41
+ # Contract Deploy
42
+ contract_address, transaction_response_deploy = deploy_intelligent_contract(
43
+ account_1,
44
+ contract_code,
45
+ "{}",
46
+ )
47
+ assert has_success_status(transaction_response_deploy)
48
+
49
+ # Get Initial State
50
+ contract_all_points_state = call_contract_method(
51
+ contract_address, account_1, "get_points", []
52
+ )
53
+ assert contract_all_points_state == {}
54
+
55
+ contract_all_bets_state = call_contract_method(
56
+ contract_address, account_1, "get_bets", []
57
+ )
58
+ assert contract_all_bets_state == {}
59
+
60
+ # Create Successful Bet
61
+ create_successful_bet_result = send_transaction(
62
+ account_1,
63
+ contract_address,
64
+ "create_bet",
65
+ ["2024-06-20", "Spain", "Italy", "1"],
66
+ )
67
+ assert has_success_status(create_successful_bet_result)
68
+ assert_dict_struct(
69
+ create_successful_bet_result,
70
+ execute_icontract_function_response_structure,
71
+ )
72
+
73
+ # Get Bets
74
+ get_bet_result = call_contract_method(contract_address, account_1, "get_bets", [])
75
+ print("~ ~ ~ ~ ~ get_bet_result", get_bet_result)
76
+ assert get_bet_result == {account_1.address: test_football_bets_win_unresolved}
77
+
78
+ # Resolve Successful Bet
79
+ resolve_successful_bet_result = send_transaction(
80
+ account_1, contract_address, "resolve_bet", ["2024-06-20_spain_italy"]
81
+ )
82
+ assert has_success_status(resolve_successful_bet_result)
83
+ assert_dict_struct(
84
+ resolve_successful_bet_result,
85
+ execute_icontract_function_response_structure,
86
+ )
87
+
88
+ # Get Bets
89
+ get_bet_result = call_contract_method(contract_address, account_1, "get_bets", [])
90
+ assert get_bet_result == {account_1.address: test_football_bets_win_resolved}
91
+
92
+ # Get Points
93
+ get_points_result = call_contract_method(
94
+ contract_address, account_1, "get_points", []
95
+ )
96
+ assert get_points_result == {account_1.address: 1}
97
+
98
+ # Get Player Points
99
+ get_player_points_result = call_contract_method(
100
+ contract_address, account_1, "get_player_points", [account_1.address]
101
+ )
102
+ assert get_player_points_result == 1
103
+
104
+ # Delete Validators - not needed for studio.genlayer.com
105
+ # delete_validators_result = post_request(payload("sim_deleteAllValidators")).json()
106
+ # assert has_success_status(delete_validators_result)
@@ -0,0 +1,107 @@
1
+ # tests/e2e/test_wizard_of_coin.py
2
+
3
+ from tools.accounts import create_new_account
4
+ from tools.request import (
5
+ deploy_intelligent_contract,
6
+ send_transaction,
7
+ call_contract_method,
8
+ payload,
9
+ post_request,
10
+ )
11
+ from tools.structure import execute_icontract_function_response_structure
12
+ from tools.response import (
13
+ assert_dict_struct,
14
+ assert_dict_exact,
15
+ has_success_status,
16
+ )
17
+ from test.football_bets_get_contract_schema_for_code import (
18
+ football_bets_contract_schema,
19
+ test_football_bets_unsuccess_unresolved,
20
+ test_football_bets_unsuccess_resolved,
21
+ )
22
+
23
+
24
+ def test_football_bets_unsuccess():
25
+ # Account
26
+ account_1 = create_new_account()
27
+ # Validators - not needed for studio.genlayer.com
28
+ # result = post_request(
29
+ # payload("sim_createRandomValidators", 5, 8, 12, ["openai"], ["gpt-4o"])
30
+ # ).json()
31
+ # assert has_success_status(result)
32
+
33
+ # Contract Schema
34
+ contract_code = open("contracts/football_bet_market.py", "r").read()
35
+ result_schema = post_request(
36
+ payload("gen_getContractSchemaForCode", contract_code)
37
+ ).json()
38
+ assert has_success_status(result_schema)
39
+ assert_dict_exact(result_schema, football_bets_contract_schema)
40
+
41
+ # Contract Deploy
42
+ contract_address, transaction_response_deploy = deploy_intelligent_contract(
43
+ account_1,
44
+ contract_code,
45
+ "{}",
46
+ )
47
+ assert has_success_status(transaction_response_deploy)
48
+
49
+ # Get Initial State
50
+ contract_all_points_state = call_contract_method(
51
+ contract_address, account_1, "get_points", []
52
+ )
53
+ assert contract_all_points_state == {}
54
+
55
+ contract_all_bets_state = call_contract_method(
56
+ contract_address, account_1, "get_bets", []
57
+ )
58
+ assert contract_all_bets_state == {}
59
+
60
+ # Create Successful Bet
61
+ create_successful_bet_result = send_transaction(
62
+ account_1,
63
+ contract_address,
64
+ "create_bet",
65
+ ["2024-06-20", "Spain", "Italy", "2"],
66
+ )
67
+ assert has_success_status(create_successful_bet_result)
68
+ assert_dict_struct(
69
+ create_successful_bet_result,
70
+ execute_icontract_function_response_structure,
71
+ )
72
+
73
+ # Get Bets
74
+ get_bet_result = call_contract_method(contract_address, account_1, "get_bets", [])
75
+ assert get_bet_result == {
76
+ account_1.address: test_football_bets_unsuccess_unresolved
77
+ }
78
+
79
+ # Resolve Successful Bet
80
+ resolve_successful_bet_result = send_transaction(
81
+ account_1, contract_address, "resolve_bet", ["2024-06-20_spain_italy"]
82
+ )
83
+ assert has_success_status(resolve_successful_bet_result)
84
+ assert_dict_struct(
85
+ resolve_successful_bet_result,
86
+ execute_icontract_function_response_structure,
87
+ )
88
+
89
+ # Get Bets
90
+ get_bet_result = call_contract_method(contract_address, account_1, "get_bets", [])
91
+ assert get_bet_result == {account_1.address: test_football_bets_unsuccess_resolved}
92
+
93
+ # Get Points
94
+ get_points_result = call_contract_method(
95
+ contract_address, account_1, "get_points", []
96
+ )
97
+ assert get_points_result == {}
98
+
99
+ # Get Player Points
100
+ get_player_points_result = call_contract_method(
101
+ contract_address, account_1, "get_player_points", [account_1.address]
102
+ )
103
+ assert get_player_points_result == 0
104
+
105
+ # Delete Validators - not needed for studio.genlayer.com
106
+ # delete_validators_result = post_request(payload("sim_deleteAllValidators")).json()
107
+ # assert has_success_status(delete_validators_result)
File without changes
@@ -0,0 +1,5 @@
1
+ from eth_account import Account
2
+
3
+
4
+ def create_new_account() -> Account:
5
+ return Account.create()
@@ -0,0 +1,224 @@
1
+ from tools.types import Address
2
+ import typing
3
+ import collections.abc
4
+ import dataclasses
5
+ import abc
6
+ import json
7
+
8
+ BITS_IN_TYPE = 3
9
+
10
+ TYPE_SPECIAL = 0
11
+ TYPE_PINT = 1
12
+ TYPE_NINT = 2
13
+ TYPE_BYTES = 3
14
+ TYPE_STR = 4
15
+ TYPE_ARR = 5
16
+ TYPE_MAP = 6
17
+
18
+ SPECIAL_NULL = (0 << BITS_IN_TYPE) | TYPE_SPECIAL
19
+ SPECIAL_FALSE = (1 << BITS_IN_TYPE) | TYPE_SPECIAL
20
+ SPECIAL_TRUE = (2 << BITS_IN_TYPE) | TYPE_SPECIAL
21
+ SPECIAL_ADDR = (3 << BITS_IN_TYPE) | TYPE_SPECIAL
22
+
23
+
24
+ class CalldataEncodable(metaclass=abc.ABCMeta):
25
+ @abc.abstractmethod
26
+ def __to_calldata__(self) -> typing.Any: ...
27
+
28
+
29
+ def encode(
30
+ x: typing.Any, *, default: typing.Callable[[typing.Any], typing.Any] = lambda x: x
31
+ ) -> bytes:
32
+ mem = bytearray()
33
+
34
+ def append_uleb128(i):
35
+ assert i >= 0
36
+ if i == 0:
37
+ mem.append(0)
38
+ while i > 0:
39
+ cur = i & 0x7F
40
+ i = i >> 7
41
+ if i > 0:
42
+ cur |= 0x80
43
+ mem.append(cur)
44
+
45
+ def impl_dict(b: collections.abc.Mapping):
46
+ keys = list(b.keys())
47
+ keys.sort()
48
+ le = len(keys)
49
+ le = (le << 3) | TYPE_MAP
50
+ append_uleb128(le)
51
+ for k in keys:
52
+ if not isinstance(k, str):
53
+ raise Exception(f"key is not string {type(k)}")
54
+ bts = k.encode("utf-8")
55
+ append_uleb128(len(bts))
56
+ mem.extend(bts)
57
+ impl(b[k])
58
+
59
+ def impl(b: typing.Any):
60
+ b = default(b)
61
+ if isinstance(b, CalldataEncodable):
62
+ b = b.__to_calldata__()
63
+ if b is None:
64
+ mem.append(SPECIAL_NULL)
65
+ elif b is True:
66
+ mem.append(SPECIAL_TRUE)
67
+ elif b is False:
68
+ mem.append(SPECIAL_FALSE)
69
+ elif isinstance(b, int):
70
+ if b >= 0:
71
+ b = (b << 3) | TYPE_PINT
72
+ append_uleb128(b)
73
+ else:
74
+ b = -b - 1
75
+ b = (b << 3) | TYPE_NINT
76
+ append_uleb128(b)
77
+ elif isinstance(b, Address):
78
+ mem.append(SPECIAL_ADDR)
79
+ mem.extend(b.as_bytes)
80
+ elif isinstance(b, bytes):
81
+ lb = len(b)
82
+ lb = (lb << 3) | TYPE_BYTES
83
+ append_uleb128(lb)
84
+ mem.extend(b)
85
+ elif isinstance(b, str):
86
+ b = b.encode("utf-8")
87
+ lb = len(b)
88
+ lb = (lb << 3) | TYPE_STR
89
+ append_uleb128(lb)
90
+ mem.extend(b)
91
+ elif isinstance(b, collections.abc.Sequence):
92
+ lb = len(b)
93
+ lb = (lb << 3) | TYPE_ARR
94
+ append_uleb128(lb)
95
+ for x in b:
96
+ impl(x)
97
+ elif isinstance(b, collections.abc.Mapping):
98
+ impl_dict(b)
99
+ elif dataclasses.is_dataclass(b):
100
+ assert not isinstance(b, type)
101
+ impl_dict(dataclasses.asdict(b))
102
+ else:
103
+ raise Exception(f"invalid type {type(b)}")
104
+
105
+ impl(x)
106
+ return bytes(mem)
107
+
108
+
109
+ def decode(mem0: collections.abc.Buffer) -> typing.Any:
110
+ mem: memoryview = memoryview(mem0)
111
+
112
+ def read_uleb128() -> int:
113
+ nonlocal mem
114
+ ret = 0
115
+ off = 0
116
+ while True:
117
+ m = mem[0]
118
+ ret = ret | ((m & 0x7F) << off)
119
+ off += 7
120
+ mem = mem[1:]
121
+ if (m & 0x80) == 0:
122
+ break
123
+ return ret
124
+
125
+ def impl() -> typing.Any:
126
+ nonlocal mem
127
+ code = read_uleb128()
128
+ typ = code & 0x7
129
+ if typ == TYPE_SPECIAL:
130
+ if code == SPECIAL_NULL:
131
+ return None
132
+ if code == SPECIAL_FALSE:
133
+ return False
134
+ if code == SPECIAL_TRUE:
135
+ return True
136
+ if code == SPECIAL_ADDR:
137
+ ret_addr = mem[: Address.SIZE]
138
+ mem = mem[Address.SIZE :]
139
+ return Address(ret_addr)
140
+ raise Exception(f"Unknown special {bin(code)} {hex(code)}")
141
+ code = code >> 3
142
+ if typ == TYPE_PINT:
143
+ return code
144
+ elif typ == TYPE_NINT:
145
+ return -code - 1
146
+ elif typ == TYPE_BYTES:
147
+ ret_bytes = mem[:code]
148
+ mem = mem[code:]
149
+ return ret_bytes
150
+ elif typ == TYPE_STR:
151
+ ret_str = mem[:code]
152
+ mem = mem[code:]
153
+ return str(ret_str, encoding="utf-8")
154
+ elif typ == TYPE_ARR:
155
+ ret_arr = []
156
+ for _i in range(code):
157
+ ret_arr.append(impl())
158
+ return ret_arr
159
+ elif typ == TYPE_MAP:
160
+ ret_dict: dict[str, typing.Any] = {}
161
+ prev = None
162
+ for _i in range(code):
163
+ le = read_uleb128()
164
+ key = str(mem[:le], encoding="utf-8")
165
+ mem = mem[le:]
166
+ if prev is not None:
167
+ assert prev < key
168
+ prev = key
169
+ assert key not in ret_dict
170
+ ret_dict[key] = impl()
171
+ return ret_dict
172
+ raise Exception(f"invalid type {typ}")
173
+
174
+ res = impl()
175
+ if len(mem) != 0:
176
+ raise Exception(f"unparsed end {bytes(mem[:5])!r}... (decoded {res})")
177
+ return res
178
+
179
+
180
+ def to_str(d: typing.Any) -> str:
181
+ buf: list[str] = []
182
+
183
+ def impl(d: typing.Any) -> None:
184
+ if d is None:
185
+ buf.append("null")
186
+ elif d is True:
187
+ buf.append("true")
188
+ elif d is False:
189
+ buf.append("false")
190
+ elif isinstance(d, str):
191
+ buf.append(json.dumps(d))
192
+ elif isinstance(d, bytes):
193
+ buf.append("b#")
194
+ buf.append(d.hex())
195
+ elif isinstance(d, int):
196
+ buf.append(str(d))
197
+ elif isinstance(d, Address):
198
+ buf.append("addr#")
199
+ buf.append(d.as_bytes.hex())
200
+ elif isinstance(d, dict):
201
+ buf.append("{")
202
+ comma = False
203
+ for k, v in d.items():
204
+ if comma:
205
+ buf.append(",")
206
+ comma = True
207
+ buf.append(json.dumps(k))
208
+ buf.append(":")
209
+ impl(v)
210
+ buf.append("}")
211
+ elif isinstance(d, list):
212
+ buf.append("[")
213
+ comma = False
214
+ for v in d:
215
+ if comma:
216
+ buf.append(",")
217
+ comma = True
218
+ impl(v)
219
+ buf.append("]")
220
+ else:
221
+ raise Exception(f"can't encode {d} to calldata")
222
+
223
+ impl(d)
224
+ return "".join(buf)