Skip to content

Commit

Permalink
Enable deploying contracts without providing abi (#1452)
Browse files Browse the repository at this point in the history
* Merge branch 'kkawula/1334-remove-unnecessary-cairo-0-tests'

* Migrate tests to use cairo 1 ERC20 contract

* Remove ERC20 contract cairo code and fixtures

* Adapt tests to the cairo 1

* Merge 'development'

* Fix test in Serilization Guide

* Fix typo in 'test_abi_parsing'

* Fix after merge

* Remove 'constructor_with_arguments.cairo' and 'constructor_without_arguments.cairo' contracts

* Add 'constructor_with_arguments.cairo' contract and update test_throws_when_calldata_not_provided

* Update 'test_constructor_arguments_contract_deploy'

* Add skiping test while cairo v1 test dir is triggered

* Update 'test_create_deployment_call_raw_supports_seed_0' and 'test_create_deployment_call_raw'

* Remove old 'constructor_with_arguments' fixture

* Update 'test_deploying_with_udc'

* Update 'constructor_with_arguments_abi' and 'constructor_with_arguments_class_hash' fixture

* Update docs example

* Add 'map' contract implementation in cairo 1

* Add fixtures for new contract

* Remove 'map_contract_declare_hahs' fixutre

* Replace old 'map_contract' fixture

* Replace old 'map_class_hash' fixture

* Update a few tests

* Update 'test_deploying_in_multicall'

* Remove 'Simple declare and deploy' paragraph from docs

* Update docs example 'Quickstart - Using Account'

* Update docs example 'Guide - test_simple_deploy

* Remove fixtures 'map_source_code' and 'map_compiled_contract'

* Fix PriceUnit assertion in 'test_account_estimate_fee_for_declare_transaction'

* Add docs test to skip because of redeclaration :(

* Remove map.cairo

* Remove 'replace_class.cairo' conatract and fixture

* Remove unused fixture 'fixture_balance_contract'

* Upadte 'test_estimate_fee_for_multiple_transactions'

* Update 'test_simulate_transactions_declare'

* Remove 'test_simulate_transactions_declare'

* Update 'simple_storage_with_event' contract to cairo 1

* Add test to skip reason='Some cairo 1 contracts compiled with v1 compiler fail with new devnet-rs'

* Remove deprecated cairo 0 fixture 'simple_storage_with_event_compiled_contract'

* Remove cairo v1 version of 'simple_storage_with_event.cairo' contract

* Remove cairo v1 contracts that have events

* Remove removed contracts from lib.cairo

* Fix 'test_deserialize_abi' v1

* Fix 'test_evenet_serialization_v1'

* Fix 'test_throws_when_cairo1_without_compiled_contract_casm_and_class_hash'

* Fix 'test_throws_when_cairo1_without_compiled_contract_casm_and_class_hash'

* Add 'Balance' contract implementation in cairo v1

* Update test for new Balance contract

* Fix funny error

* Remove cairo 0 'balance' contract

* Remove cairo 0 'balance_struct_event' contract

* Add folder with cairo 0 contracs abi; Delete 'balance_struxt_event' and 'complex_abi' contracts

* Remove unused 'mock_account.cairo' contract

* Remove unused 'contract.cairo' contract

* Remove unused cairo 0 openzeppelin contracts

* Remove unused 'Upgradable.cairo' contract

* Remove usage of cairo 0 account contract; Add cairo 1 account contract

* Fix 'test_compute_sierra_class_hash'

* Add 'test_simple_declare_and_deploy' to skip

* Remove cairo 0 'account_with_validate_deploy' contract

* Remove cairo 0 contracts compiling script and workflow

* Fix github workflows checks

* Revert "Fix github workflows checks"

This reverts commit fd9c3d9.

* Reapply "Fix github workflows checks"

This reverts commit fef6821.

* Fix github workflows checks

* Fix workflows

* Revert "Fix github workflows checks"

This reverts commit 3fd4e7b.

* Add download

* Fix 'test_deploy_account_v1'

* Skip 'test_deploy_account_v1' for contract from v1 directory

* Remove 'test_sign_invoke_v1_for_fee_estimation' (sign_decalre_v1)

* Remove unused fixture 'deployed_balance_contract' (declare_v1)

* Remove 'declare_v1' method from 'Contract' class

* Remove 'sign_declare_v1' method from 'Account' and 'BaseAccount' class

* Update docs 'deploying_contracts' (remove declare_v1)

* Enable deploying contracts without providing abi

* Fix 'test_deploy_contract_v3_without_abi' test

* Update vaildating calldata

* Remove 'test_throws_when_calldata_provided_without_abi'

* Create 'test_constructor_arguments_contract_deploy_without_abi'

* Remove 'test_throws_when_calldata_not_provided'

* Rename 'is_valid_calldata' to '_is_list_of_ints_or_strings'

* Add 'test_throws_when_calldata_provided_without_abi'

* Lint

* Update starknet_py/tests/e2e/docs/code_examples/test_contract.py

Co-authored-by: Franciszek Job <54181625+franciszekjob@users.noreply.github.com>

* Update docstring for '_is_list_of_ints_or_strings'

* Update starknet_py/tests/e2e/deploy/deployer_test.py

Co-authored-by: Franciszek Job <54181625+franciszekjob@users.noreply.github.com>

* Update starknet_py/net/udc_deployer/deployer.py

Co-authored-by: Franciszek Job <54181625+franciszekjob@users.noreply.github.com>

* Update starknet_py/tests/e2e/deploy/deployer_test.py

Co-authored-by: Franciszek Job <54181625+franciszekjob@users.noreply.github.com>

* Fix '_is_list_of_ints_or_strings' docstring

* Fix abi conditions

* Add empty line for readability

* Fix after merge

* Fix 'create_contract_deployment' condition

---------

Co-authored-by: Franciszek Job <54181625+franciszekjob@users.noreply.github.com>
  • Loading branch information
kkawula and franciszekjob authored Aug 29, 2024
1 parent d8b2436 commit 35845a2
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 291 deletions.
14 changes: 10 additions & 4 deletions starknet_py/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ async def deploy_contract_v1(
async def deploy_contract_v3(
account: BaseAccount,
class_hash: Hash,
abi: List,
abi: Optional[List] = None,
constructor_args: Optional[Union[List, Dict]] = None,
*,
deployer_address: AddressRepresentation = DEFAULT_DEPLOYER_ADDRESS,
Expand Down Expand Up @@ -1012,9 +1012,15 @@ async def deploy_contract_v3(
auto_estimate=auto_estimate,
)

deployed_contract = Contract(
provider=account, address=address, abi=abi, cairo_version=cairo_version
)
if abi is not None:
deployed_contract = Contract(
provider=account, address=address, abi=abi, cairo_version=cairo_version
)
else:
deployed_contract = await Contract.from_address(
address=address, provider=account
)

deploy_result = DeployResult(
hash=res.transaction_hash,
_client=account.client,
Expand Down
30 changes: 24 additions & 6 deletions starknet_py/net/udc_deployer/deployer.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,18 @@ def create_contract_deployment(
:param calldata: Constructor args of the contract to be deployed.
:return: NamedTuple with call and address of the contract to be deployed.
"""
if not abi and calldata:
raise ValueError("Argument calldata was provided without an ABI.")

raw_calldata = translate_constructor_args(
abi=abi or [], constructor_args=calldata, cairo_version=cairo_version
)
raw_calldata = None

if calldata and abi is None:
if not _is_list_of_ints_or_strings(calldata):
raise ValueError(
"Argument calldata was provided without an ABI. It cannot be serialized."
)
raw_calldata = [int_from_hex(x) for x in calldata]
elif calldata and abi is not None:
raw_calldata = translate_constructor_args(
abi=abi or [], constructor_args=calldata, cairo_version=cairo_version
)

return self.create_contract_deployment_raw(
class_hash=class_hash, salt=salt, raw_calldata=raw_calldata
Expand Down Expand Up @@ -176,3 +182,15 @@ def _get_random_salt() -> int:
_deployer_serializer = serializer_for_function(
_deployer_abi.functions["deployContract"]
)


def _is_list_of_ints_or_strings(data: Union[List, dict]) -> bool:
"""
Checks if the given data is a list containing only strings or integers.
:param data: Constructor args (calldata) of the contract to be deployed.
:return: True if the data is a list of strings or integers, False otherwise.
"""
if isinstance(data, list):
return all(isinstance(x, (int, str)) for x in data)
return False
17 changes: 0 additions & 17 deletions starknet_py/tests/e2e/account/account_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,23 +673,6 @@ async def test_sign_invoke_v3_for_fee_estimation(account, map_contract):
assert estimation.overall_fee > 0


# TODO (#1419): Fix contract redeclaration
@pytest.mark.skip(reason="Redeclaration occurred")
@pytest.mark.asyncio
async def test_sign_declare_v1_for_fee_estimation(account, map_compiled_contract):
transaction = await account.sign_declare_v1(
compiled_contract=map_compiled_contract, max_fee=MAX_FEE
)

estimate_fee_transaction = await account.sign_for_fee_estimate(transaction)
assert estimate_fee_transaction.version == transaction.version + 2**128

estimation = await account.client.estimate_fee(estimate_fee_transaction)
assert isinstance(estimation, EstimatedFee)
assert estimation.unit == PriceUnit.WEI
assert estimation.overall_fee > 0


@pytest.mark.asyncio
async def test_sign_deploy_account_v1_for_fee_estimation(
client, deploy_account_details_factory
Expand Down
86 changes: 63 additions & 23 deletions starknet_py/tests/e2e/deploy/deployer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,41 @@ async def test_default_deploy_with_class_hash(account, map_class_hash):
assert contract_deployment.address != 0


@pytest.mark.asyncio
async def test_throws_when_calldata_provided_without_abi(map_class_hash):
deployer = Deployer()

with pytest.raises(ValueError, match="calldata was provided without an ABI."):
deployer.create_contract_deployment(
class_hash=map_class_hash, calldata=[12, 34]
)


@pytest.mark.skipif(
"--contract_dir=v2" not in sys.argv,
reason="Contract exists only in v2 directory",
)
@pytest.mark.asyncio
async def test_throws_when_calldata_not_provided(constructor_with_arguments_abi):
deployer = Deployer()
@pytest.mark.parametrize("calldata", [[10, 1, 2, 3, 3, 1, 2, 3, 12, 99]])
async def test_constructor_arguments_contract_deploy_without_abi(
account,
constructor_with_arguments_class_hash,
calldata,
):
deployer = Deployer(account_address=account.address)

with pytest.raises(
ValueError,
match="Provided contract has a constructor and no arguments were provided.",
):
deployer.create_contract_deployment(
class_hash=1234, abi=constructor_with_arguments_abi, cairo_version=1
)
deploy_call, contract_address = deployer.create_contract_deployment(
class_hash=constructor_with_arguments_class_hash,
calldata=calldata,
)

deploy_invoke_transaction = await account.sign_invoke_v1(
deploy_call, max_fee=MAX_FEE
)
resp = await account.client.send_transaction(deploy_invoke_transaction)
await account.client.wait_for_tx(resp.transaction_hash)

contract = await Contract.from_address(address=contract_address, provider=account)

result = (await contract.functions["get"].call(block_number="latest"))[0]
unwrapped_result = (result[0], result[1], result[2], dict(result[3]))
expected_result = (
10,
(1, (2, 3)),
sum([1, 2, 3]),
{"value": 12, "nested_struct": {"value": 99}},
)
assert unwrapped_result == expected_result


@pytest.mark.skipif(
Expand Down Expand Up @@ -82,7 +92,6 @@ async def test_constructor_arguments_contract_deploy(
class_hash=constructor_with_arguments_class_hash,
abi=constructor_with_arguments_abi,
calldata=calldata,
cairo_version=1,
)

deploy_invoke_transaction = await account.sign_invoke_v1(
Expand All @@ -95,7 +104,6 @@ async def test_constructor_arguments_contract_deploy(
address=contract_address,
abi=constructor_with_arguments_abi,
provider=account,
cairo_version=1,
)

result = (await contract.functions["get"].call(block_number="latest"))[0]
Expand All @@ -108,6 +116,39 @@ async def test_constructor_arguments_contract_deploy(
)


@pytest.mark.skipif(
"--contract_dir=v1" in sys.argv,
reason="Contract exists only in v2 directory",
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"calldata",
[
[10, (1, (2, 3)), [1, 2, 3], {"value": 12, "nested_struct": {"value": 99}}],
{
"single_value": 10,
"tuple": (1, (2, 3)),
"arr": [1, 2, 3],
"dict": {"value": 12, "nested_struct": {"value": 99}},
},
],
)
async def test_throws_when_calldata_provided_without_abi(
account,
constructor_with_arguments_class_hash,
calldata,
):
deployer = Deployer(account_address=account.address)

with pytest.raises(
ValueError,
match="Argument calldata was provided without an ABI. It cannot be serialized.",
):
deployer.create_contract_deployment(
class_hash=constructor_with_arguments_class_hash, calldata=calldata
)


@pytest.mark.asyncio
@pytest.mark.parametrize(
"salt, pass_account_address", [(1, True), (2, False), (None, True), (None, False)]
Expand Down Expand Up @@ -161,7 +202,7 @@ async def test_create_deployment_call_raw(
deployer = Deployer(account_address=account.address)

raw_calldata = translate_constructor_args(
abi=constructor_with_arguments_abi, constructor_args=calldata, cairo_version=1
abi=constructor_with_arguments_abi, constructor_args=calldata
)

(
Expand Down Expand Up @@ -204,7 +245,6 @@ async def test_create_deployment_call_raw_supports_seed_0(
raw_calldata = translate_constructor_args(
abi=constructor_with_arguments_abi,
constructor_args=sample_calldata,
cairo_version=1,
)

expected_address = compute_address(
Expand Down
26 changes: 26 additions & 0 deletions starknet_py/tests/e2e/docs/code_examples/test_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,29 @@ async def test_deploy_contract_v3(account, cairo1_hello_starknet_class_hash: int
contract_address=contract.address
)
assert class_hash == cairo1_hello_starknet_class_hash


@pytest.mark.asyncio
async def test_deploy_contract_v3_without_abi(
account, cairo1_hello_starknet_class_hash: int
):
deploy_result = await Contract.deploy_contract_v3(
class_hash=cairo1_hello_starknet_class_hash,
account=account,
l1_resource_bounds=ResourceBounds(
max_amount=int(1e5), max_price_per_unit=int(1e13)
),
)
await deploy_result.wait_for_acceptance()

contract = deploy_result.deployed_contract
assert isinstance(contract.address, int)
assert len(contract.functions) == 2

transaction = await account.client.get_transaction(tx_hash=deploy_result.hash)
assert isinstance(transaction, InvokeTransactionV3)

class_hash = await account.client.get_class_hash_at(
contract_address=contract.address
)
assert class_hash == cairo1_hello_starknet_class_hash

This file was deleted.

Loading

0 comments on commit 35845a2

Please sign in to comment.