Skip to content

Commit c606c31

Browse files
committed
update contract verify/unverify to work with new service
1 parent 4cdaeff commit c606c31

2 files changed

Lines changed: 98 additions & 44 deletions

File tree

multiversx_sdk_cli/cli_contracts.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@
2828
from multiversx_sdk_cli.config import get_config_for_network_providers
2929
from multiversx_sdk_cli.config_env import MxpyEnv
3030
from multiversx_sdk_cli.constants import NUMBER_OF_SHARDS
31-
from multiversx_sdk_cli.contract_verification import trigger_contract_verification
31+
from multiversx_sdk_cli.contract_verification import (
32+
trigger_contract_verification,
33+
trigger_contract_verification_from_existing,
34+
)
3235
from multiversx_sdk_cli.docker import is_docker_installed, run_docker
3336
from multiversx_sdk_cli.errors import BadUsage, DockerMissingError, QueryContractError
3437
from multiversx_sdk_cli.ux import show_warning
@@ -160,6 +163,34 @@ def setup_parser(args: list[str], subparsers: Any) -> Any:
160163
)
161164
sub.set_defaults(func=verify)
162165

166+
sub = cli_shared.add_command_subparser(
167+
subparsers,
168+
"contract",
169+
"verify-from-existing",
170+
"Verify the authenticity of the code of a deployed Smart Contract from an already verified Smart Contract",
171+
)
172+
173+
_add_contract_arg(sub)
174+
sub.add_argument(
175+
"--verified-contract",
176+
required=True,
177+
help="the bech32 address of the already verified contract",
178+
)
179+
sub.add_argument(
180+
"--verifier-url",
181+
required=True,
182+
help="the url of the service that validates the contract",
183+
)
184+
sub.add_argument(
185+
"--skip-confirmation",
186+
"-y",
187+
dest="skip_confirmation",
188+
action="store_true",
189+
default=False,
190+
help="can be used to skip the confirmation prompt",
191+
)
192+
sub.set_defaults(func=verify_from_existing)
193+
163194
sub = cli_shared.add_command_subparser(
164195
subparsers,
165196
"contract",
@@ -568,6 +599,23 @@ def verify(args: Any) -> None:
568599
logger.info("Contract verification request completed!")
569600

570601

602+
def verify_from_existing(args: Any) -> None:
603+
if not args.skip_confirmation:
604+
response = input(
605+
"Are you sure you want to verify the contract? This will publish the contract's source code, which will be displayed on the MultiversX Explorer (y/n): "
606+
)
607+
if response.lower() != "y":
608+
logger.info("Contract verification cancelled.")
609+
return
610+
611+
contract = Address.new_from_bech32(args.contract)
612+
verified_contract = Address.new_from_bech32(args.verified_contract)
613+
verifier_url = args.verifier_url
614+
615+
trigger_contract_verification_from_existing(contract, verified_contract, verifier_url)
616+
logger.info("Contract verification request completed!")
617+
618+
571619
def unverify(args: Any) -> None:
572620
account = cli_shared.prepare_account(args)
573621
contract: str = args.contract
@@ -593,7 +641,7 @@ def unverify(args: Any) -> None:
593641
headers = {"Content-type": "application/json"}
594642
response = requests.delete(verifier_url, json=request_payload, headers=headers)
595643
logger.info(f"Your request to unverify contract {contract} was submitted.")
596-
print(response.json().get("message"))
644+
utils.dump_out_json(response.json())
597645

598646

599647
def do_reproducible_build(args: Any):

multiversx_sdk_cli/contract_verification.py

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@
1111
from multiversx_sdk_cli.errors import KnownError
1212
from multiversx_sdk_cli.utils import dump_out_json, read_json_file
1313

14-
HTTP_REQUEST_TIMEOUT = 408
15-
HTTP_SUCCESS = 200
16-
1714
logger = logging.getLogger("cli.contracts.verifier")
1815

1916

@@ -94,26 +91,31 @@ def trigger_contract_verification(
9491
request_dictionary = contract_verification.to_dictionary()
9592

9693
url = f"{verifier_url}/verifier"
97-
status_code, message, data = _do_post(url, request_dictionary)
98-
99-
if status_code == HTTP_REQUEST_TIMEOUT:
100-
task_id = data.get("taskId", "")
101-
102-
if task_id:
103-
query_status_with_task_id(verifier_url, task_id)
104-
else:
105-
dump_out_json(data)
106-
elif status_code != HTTP_SUCCESS:
107-
dump_out_json(data)
108-
raise KnownError(f"Cannot verify contract: {message}")
109-
else:
110-
status = data.get("status", "")
111-
if status:
112-
logger.info(f"Task status: {status}")
113-
dump_out_json(data)
114-
else:
115-
task_id = data.get("taskId", "")
116-
query_status_with_task_id(verifier_url, task_id)
94+
response = _do_post(url, request_dictionary)
95+
96+
task_id: str = response.get("taskId", "")
97+
if not task_id:
98+
raise KnownError("No task ID received from the verifier.")
99+
100+
logger.info(f"Contract verification triggered successfully. Task ID: {task_id}")
101+
query_status_with_task_id(verifier_url, task_id)
102+
103+
104+
def trigger_contract_verification_from_existing(contract: Address, verified_contract: Address, verifier_url: str):
105+
payload = {
106+
"contract": contract.to_bech32(),
107+
"existingVerifiedContract": verified_contract.to_bech32(),
108+
}
109+
110+
url = f"{verifier_url}/verifier/from-existing"
111+
response = _do_post(url, payload)
112+
113+
task_id: str = response.get("taskId", "")
114+
if not task_id:
115+
raise KnownError("No task ID received from the verifier.")
116+
117+
logger.info(f"Contract verification triggered successfully. Task ID: {task_id}")
118+
query_status_with_task_id(verifier_url, task_id)
117119

118120

119121
def _create_request_signature(account: IAccount, contract_address: Address, request_payload: bytes) -> bytes:
@@ -128,42 +130,46 @@ def query_status_with_task_id(url: str, task_id: str, interval: int = 10):
128130
old_status = ""
129131

130132
while True:
131-
_, _, response = _do_get(f"{url}/tasks/{task_id}")
133+
response = _do_get(f"{url}/tasks/{task_id}")
134+
try:
135+
response.raise_for_status()
136+
except requests.HTTPError as error:
137+
data = response.json()
138+
message = data.get("message", str(error))
139+
raise KnownError(f"Cannot verify contract: {message}", error)
140+
141+
response = response.json()
132142
status = response.get("status", "")
133143

134-
if status == "finished":
144+
if status == "error":
145+
logger.error("Verification failed!")
146+
dump_out_json(response)
147+
break
148+
elif status == "finished":
135149
logger.info("Verification finished!")
136150
dump_out_json(response)
137151
break
138152
elif status != old_status:
139153
logger.info(f"Task status: {status}")
140-
dump_out_json(response)
141154
old_status = status
142155

143156
time.sleep(interval)
144157

145158

146-
def _do_post(url: str, payload: Any) -> tuple[int, str, dict[str, Any]]:
159+
def _do_post(url: str, payload: Any) -> dict[str, str]:
147160
logger.debug(f"_do_post() to {url}")
148161
response = requests.post(url, json=payload)
149-
150162
try:
163+
response.raise_for_status()
164+
except requests.HTTPError as error:
151165
data = response.json()
152-
message = data.get("message", "")
153-
return response.status_code, message, data
154-
except Exception as error:
155-
logger.error(f"Erroneous response from {url}: {response.text}")
156-
raise KnownError(f"Cannot parse response from {url}", error)
166+
message = data.get("message", str(error))
167+
raise KnownError(f"Cannot verify contract: {message}", error)
157168

169+
return response.json()
158170

159-
def _do_get(url: str) -> tuple[int, str, dict[str, Any]]:
171+
172+
def _do_get(url: str) -> requests.Response:
160173
logger.debug(f"_do_get() from {url}")
161174
response = requests.get(url)
162-
163-
try:
164-
data = response.json()
165-
message = data.get("message", "")
166-
return response.status_code, message, data
167-
except Exception as error:
168-
logger.error(f"Erroneous response from {url}: {response.text}")
169-
raise KnownError(f"Cannot parse response from {url}", error)
175+
return response

0 commit comments

Comments
 (0)