Package: ape-starknet
Quick StartPlugins for theStarkNet Ethereum L2 networks.Dependenciespython3version 3.8 or greater, python3-devInstallationviapipYou can install the latest release viapip:pipinstallape-starknetviasetuptoolsYou can clone the repository and usesetuptoolsfor the most up-to-date version:gitclonehttps://github.com/ApeWorX/ape-starknet.gitcdape-starknet
python3setup.pyinstallQuick UsageAccount ManagementAccounts are used to execute transactions and sign call data.
Accounts are smart contracts in Starknet.Out of the box,ape-starknetcomes with development accounts.
Access them like this:fromapeimportaccountscontainer=accounts.containers["starknet"]owner=container.test_accounts[0]See the section below aboutTestingto learn more about test accounts.However, when using a live network, you will have to import or create an account first.Importing an AccountTo import an account, use theimportcommand:apestarknetaccountsimport<ALIAS>\--networktestnet,testnet2\--address0x6b7111AA4111e5B2229c3332B66696888164440A773333143333B383333a183\--class-hash"0x025ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918"--salt123The command above is using a network value oftestnet,testnet2, meaning both Starknet's Goerli testnet and Goerli testnet2 networks.
You can run the import command more than once to add more networks at a later time.
To add all networks at once, you can also use a--networkvalue ofstarknet.If the account is already added, you can omit the--addressflag and use the calculated one instead.
If you know the salt the account used to calculate its address, you can provide that with the--saltflag.
This will allow future deployments to use the same address.Importing accounts is complex.
A common use-case is to import your Argent-X wallet.
To do this, you can use the following command:apestarknetaccountsimport<ArgentX-Alias>\--networkstarknet\--address0x6b7111AA4111e5B2229c3332B66696888164440A773333143333B383333a183\--class-hashargentxAnd then export your Argent-X private key from the app and paste it in the CLI prompt.
Now, you can use your argent-x account to fund and create other accounts!Creating an AccountTo create a new account, you can use thecreatecommand:apestarknetaccountscreate<NEW-ALIAS>By default, new accounts use the Open Zeppelin account contract implementation.
However, if you want to change the class, use the--class-hashoption:CLASS_HASH="0x1a7820094feaf82d53f53f214b81292d717e7bb9a92bb2488092cd306f3993f"apestarknetaccountscreate<NEW-ALIAS>--class-hash"${CLASS_HASH}"NOTE: You may also need to change the constructor calldata using the--constructor-calldataflag when using a different account contract type.Thecreatecommand will first generate the public and private key combination and store a local keyfile for the account.
However, it does not deploy the account.
The reason it does not deploy is that the account needs funding to pay for its deployment and there are several ways to achieve this.
Seethis sectionof the Starknet official guides for more information.Deploying an AccountTo deploy the new account, use thedeploycommand:apestarknetaccountsdeploy<NEW-ALIAS>--networktestnetThis only works if the account has been funded.
For convenience purposes, if you have another account with funds, you can use that account to fund the deployment of this one using the--funderoption:apestarknetaccountsdeploy<NEW-ALIAS>--networktestnet--funder<EXISTING-FUNDED-ALIAS>NOTE: You cannot use an Ethereum account to send funds to a Starknet account directly.
You must use theStarkNet L2 bridgeto transfer existing Goerli L1 ETH to and from the L2 account.Listing AccountsSee your accounts and all of their deployment addresses:apestarknetaccountslistshows:Alias-<ALIAS>
Publickey-0x123444444d716666dd88882bE2e99991555DE1c7
Classhash-0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918
Contractaddress(testnet)-0x6b7111AA4111e5B2229c3332B66696888164440A773333143333B383333a183
Contractaddress(mainnet)-0x7873113A4111e5B2229c3332B66696388163440A373333143333B3833332122Deleting an AccountYou can also delete accounts:apestarknetaccountsdelete<ALIAS>--networktestnet,testnet2Thedeletecommand differs based on its values of--networkand--address:To delete all deployments on a given network, use the--networkoption without--address.To delete all deployments matching an address (regardless of network), use the--addressoption without--network.To delete a deployment on a network with a particular address, use both--networkand--address.Exclude both options to delete the whole account.Note you can also specify multiple networks, the same asimport.Auto-Sign MessageWhile generally bad practice, sometimes it is necessary to have unlocked keyfile accounts auto-signing messages.
An example would be during testnet automated deployments.
To achieve this, use theset_autosign()method available on the keyfile accounts:importkeyringfromapeimportaccounts# Use keyring package to store secretspassword=keyring.get_password("starknet-testnet-automations","ci-shared-account")testnet_account=accounts.load("starknet-testnet-account")testnet_account.set_autosign(True,passphrase=password)# Won't prompt for signing or unlockingtestnet_account.sign_message([123])Declare and Deploy ContractsIn Starknet, you can declare contract types by publishing them to the chain.
This allows other contracts to create instances of them using thedeploy system call.To declare a contract usingape-starknet, do the following (in a script or console):fromapeimportaccounts,projectaccount=accounts.load("<MY_STARK_ACCOUNT>")declaration=account.declare(project.MyContract)print(declaration.class_hash)Then, you can use thedeploymethod to deploy the contracts.NOTE: Thedeploymethod inape-starknetmakes an invoke-function call against the Starknet public UDC contract.
Learn more about UDC contractshere.fromapeimportaccounts,project# This only works if `project.MyContract` was declared previously.# The class hash is not necessary as an argument. Ape will look it up.account=accounts.load("<MY_STARK_ACCOUNT>")account.deploy(project.MyContact)You can also deploy contracts by doing:fromapeimportaccounts,projectaccount=accounts.load("<MY_STARK_ACCOUNT>")my_contract=project.MyContract.deploy(sender=account)Alternatively, you can use the class hash in adeploy()system call in a local factory contract.
Let's say for example I have the following Cairo factory contract:from starkware.cairo.common.alloc import alloc
from starkware.starknet.common.syscalls import deploy
from starkware.cairo.common.cairo_builtins import HashBuiltin

@storage_var
func class_hash() -> (class_hash: felt) {
}

@storage_var
func salt() -> (value: felt) {
}

@constructor
func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(cls_hash: felt) {
    class_hash.write(value=cls_hash);
    return ();
}

@external
func deploy_my_contract{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {
    let (cls_hash) = class_hash.read();
    let (current_salt) = salt.read();
    let (ctor_calldata) = alloc();
    let (contract_addr) = deploy(
        class_hash=cls_hash,
        contract_address_salt=current_salt,
        constructor_calldata_size=0,
        constructor_calldata=ctor_calldata,
        deploy_from_zero=FALSE,
    );
    salt.write(value=current_salt + 1);
    return ();
}This contract accepts a class hash of a declared contract deploys it.
The following example shows how to use this factory class to deploy other contracts:fromapeimportContract,accounts,networks,projectaccount=accounts.load("<MY_STARK_ACCOUNT>")declaration=account.declare(project.MyContract)# NOTE: Assuming you have a contract named 'ContractFactory'.factory=project.ContractFactory.deploy(declaration.class_hash,sender=account)call_result=factory.deploy_my_contract()contract_address=networks.starknet.decode_address(call_result)contract=Contract(contract_address,contract_type=project.MyContract.contract_type)Contract InteractionAfter you have deployed your contracts, you can begin interacting with them.deploymethods return a contract instance from which you can call methods on:fromapeimportprojectcontract=project.MyContract.deploy(sender=account)# Interact with deployed contractreceipt=contract.my_mutable_method(123)value=contract.my_view_method()You can access the return data from a mutable method's receipt:receipt=contract.my_mutable_method(123)result=receipt.return_valueInclude a sender to delegate the transaction to an account contract:fromapeimportaccountsaccount=accounts.load("my_account")receipt=contract.my_mutable_method(123,sender=account)NOTE: Currently, to pass in arrays as arguments, you have to also include the array size beforehand:receipt=contract.store_my_list(3,[1,2,3])TestingAccountsYou can usestarknet-devnetaccounts in your tests.importpytestimportape@pytest.fixturedefdevnet_accounts():returnape.accounts.containers["starknet"].test_accounts@pytest.fixturedefowner(devnet_accounts):returndevnet_accounts[0]Additionally, any accounts deployed in the local network arenotsaved to disk and are ephemeral.importpytestimportape@pytest.fixture(scope="session")defephemeral_account():accounts=ape.accounts.containers["starknet"]accounts.deploy_account("ALIAS")# This account only exists in the devnet and is not a key-file account.returnaccounts.load("ALIAS")Paying FeesStarknet fees are currently paid in ETH, which is an ERC-20 on the Starknet chain.
To check your account balance (in ETH), use thebalanceproperty on the account:fromapeimportaccountsacct=accounts.load("Alias")print(acct.balance)If your account has a positive balance, you can begin paying fees!To pay fees, you can either manually set themax_feekwarg on an invoke-transaction:receipt=contract.my_mutable_method(123,max_fee=2900000000000)NOTE: By not setting themax_fee, it will automatically get set to the value returned from the providerestimate_gas_cost()call.
You donotneed to callestimate_gas_cost()explicitly.Mainnet Alpha Whitelist Deployment TokenCurrently, to deploy to Alpha-Mainnet, your contract needs to be whitelisted.
You can provide your WL token in a variety of ways.Via Python code:fromapeimportprojectmy_contract=project.MyContract.deploy(token="MY_TOKEN")Via an Environment Variable:exportALPHA_MAINNET_WL_DEPLOY_TOKEN="MY_TOKEN"DevelopmentThis project is in development and should be considered a beta.
Things might not be in their final state and breaking changes may occur.
Comments, questions, criticisms and pull requests are welcomed.