forked from coccoinomane/web3cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathabi_controller.py
More file actions
169 lines (159 loc) · 5.75 KB
/
Copy pathabi_controller.py
File metadata and controls
169 lines (159 loc) · 5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import argparse
from cement import ex
from web3.types import ABI
from web3cli.exceptions import Web3CliError
from web3cli.framework.controller import Controller
from web3cli.helpers import args
from web3cli.helpers.render import render
from web3core.helpers.abi import decode_function_data as _decode_function_data
from web3core.helpers.abi import (
filter_abi_by_type_and_name,
get_event_full_signatures,
get_event_signatures,
get_function_full_signatures,
get_function_signatures,
)
from web3core.helpers.contract import get_web3_contract
from web3core.models.contract import Contract, ContractType
class AbiController(Controller):
"""Handler of the `w3 abi` commands"""
class Meta:
label = "abi"
help = "extract info about a contract's functions and events"
stacked_type = "nested"
stacked_on = "base"
@ex(
help="List the functions in the given contract, contract type or ABI string, with signatures",
arguments=[
(
["contract"],
{
"help": "Name of the contract or contract type in the database",
"nargs": "?",
},
),
args.contract_abi(
help="Pass the ABI of the contract instead, as a string or file"
),
(
["--full", "-f"],
{
"help": "Show full signatures (with parameter types)",
"action": argparse.BooleanOptionalAction,
"default": True,
},
),
args.chain(),
],
aliases=["fns", "fn", "f"],
)
def functions(self) -> None:
abi = self.parse_abi()
functions = (
get_function_full_signatures(abi)
if self.app.pargs.full
else get_function_signatures(abi)
)
render(self.app, sorted(functions, key=str.lower))
@ex(
help="List the events in the given contract, contract type or ABI string, with signatures",
arguments=[
(
["contract"],
{
"help": "Name of the contract or contract type in the database.",
"nargs": "?",
},
),
args.contract_abi(
help="Pass the ABI of the contract instead, as a string or file"
),
(
["--full", "-f"],
{
"help": "Show full signatures (with parameter types)",
"action": argparse.BooleanOptionalAction,
"default": True,
},
),
args.chain(),
],
aliases=["evs", "ev", "e"],
)
def events(self) -> None:
abi = self.parse_abi()
events = (
get_event_full_signatures(abi)
if self.app.pargs.full
else get_event_signatures(abi)
)
render(self.app, sorted(events, key=str.lower))
@ex(
help="Show the ABI of a specific contract function or event",
arguments=[
(
["contract"],
{"help": "Name of the contract or contract type in the database"},
),
(["function_name"], {"help": "Name of the function or event"}),
args.chain(),
],
)
def get(self) -> None:
abi = self.parse_abi()
obj = filter_abi_by_type_and_name(
abi, type=None, name=self.app.pargs.function_name
)
if not obj:
self.app.log.warning(
f"Function or event '{self.app.pargs.function_name}' not found"
)
render(self.app, obj)
@ex(
help="Given input data for a contract function, return its decoded arguments and, optionally, the function signature",
arguments=[
(["contract"], {"help": "Name of the contract"}),
(["data"], {"help": "Input data"}),
(
["--name"],
{"help": "Specify the function name rather than its selector"},
),
(
["--signature"],
{
"help": "Include function signature in the output, with key __function_signature",
"action": "store_true",
},
),
args.chain(),
],
)
def decode_function_data(self) -> None:
web3_contract = get_web3_contract(self.app.pargs.contract, self.app.chain)
params, signature = _decode_function_data(
web3_contract.abi, self.app.pargs.data, self.app.pargs.name
)
if self.app.pargs.signature:
params["__function_signature"] = signature
render(self.app, params)
def parse_abi(self) -> ABI:
"""Parse the 'contract' and '--abi' arguments and return the ABI"""
# Contract name given, try to retrieve the ABI from the database
if self.app.pargs.contract:
# Try to retrieve ABI from contracts table
contract = Contract.get_by_name_and_chain(
self.app.pargs.contract, self.app.chain.name
)
if contract:
return contract.resolve_abi()
# Try to retrieve ABI from contract_types table
contract_type = ContractType.get_by_name(self.app.pargs.contract)
if contract_type:
return contract_type.abi
# Contract not found
raise Web3CliError(f"Contract {self.app.pargs.contract} not found")
# No contract name given, try to parse the ABI as string or file
if self.app.pargs.abi:
return args.parse_contract_abi(self.app)
# Should never happen
raise Web3CliError("ABI not found")