Skip to main content

ape-starknet: An ape plugin for the StarkNet networks

Project description

Quick Start

Plugins for the StarkNet Ethereum L2 networks.

Dependencies

  • python3 version 3.8 or greater, python3-dev

Installation

via pip

You can install the latest release via pip:

pip install ape-starknet

via setuptools

You can clone the repository and use setuptools for the most up-to-date version:

git clone https://github.com/ApeWorX/ape-starknet.git
cd ape-starknet
python3 setup.py install

Quick Usage

Account Management

Accounts are used to execute transactions and sign call data. Accounts are smart contracts in Starknet.

Out of the box, ape-starknet comes with development accounts. Access them like this:

from ape import accounts

container = accounts.containers["starknet"]
owner = container.test_accounts[0]

See the section below about Testing to learn more about test accounts.

However, when using a live network, you will have to import or create an account first.

To import an account, use the import command:

ape starknet accounts import <ALIAS> --address 0x6b7111AA4111e5B2229c3332B66696888164440A773333143333B383333a183 --network starknet:testnet

To create a new account, you will use the create command:

ape starknet accounts create <NEW-ALIAS> --network starknet:testnet

The create command will first generate the public and private key combination and store a local keyfile for the account. However, it does not deploy the account automatically. The reason it does not deploy automatically is that the account needs funding to pay for its deployment and there are several ways to achieve this. See this section of the Starknet official guides for more information.

NOTE: You cannot use an Ethereum account to send funds to a Starknet account directly. You must use the StarkNet L2 bridge to transfer existing Goerli L1 ETH to and from the L2 account.

For convenience purposes, if you already have a Starknet account in Ape, you can use that account to fund the creation of new ones. To do this, use the --deployment-funder flag to specify the funder alias of your other account:

ape starknet accounts create <NEW-ALIAS> --network starknet:testnet --deployment-funder <EXISTING-ALIAS>

Otherwise, after you have funded your newly created account an alternative way, you can use the deploy command to deploy it:

ape starknet accounts deploy <NEW-ALIAS>

You can create the same account in multiple networks by adjusting the --network flag:

ape starknet accounts create <ALIAS> --network starknet:mainnet

See your accounts and all of their deployment addresses:

ape starknet accounts list

shows:

Alias                      - <ALIAS>
Public key                 - 0x123444444d716666dd88882bE2e99991555DE1c7
Contract address (testnet) - 0x6b7111AA4111e5B2229c3332B66696888164440A773333143333B383333a183
Contract address (mainnet) - 0x7873113A4111e5B2229c3332B66696388163440A373333143333B3833332122

You can also delete accounts:

ape starknet accounts delete <ALIAS> --network starknet:testnet

NOTE: You don't have to specify the network if your account is only deployed to a single network.

Auto-Sign Message

While 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 the set_autosign() method available on the keyfile accounts:

import keyring
from ape import accounts

# Use keyring package to store secrets
password = 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 unlocking
testnet_account.sign_message([123])

Declare and Deploy Contracts

In Starknet, you can declare contract types by publishing them to the chain. This allows other contracts to create instances of them using the deploy system call.

To declare a contract using ape-starknet, do the following (in a script or console):

from ape import accounts, project

account = accounts.load("<MY_STARK_ACCOUNT>")
declaration = account.declare(project.MyContract)
print(declaration.class_hash)

Then, you can use the deploy method to deploy the contracts. NOTE: The deploy method in ape-starknet makes an invoke-function call against the Starknet public UDC contract. Learn more about UDC contracts here.

from ape import accounts, 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:

from ape import accounts, project

account = accounts.load("<MY_STARK_ACCOUNT>")
my_contract = project.MyContract.deploy(sender=account)

Alternatively, you can use the class hash in a deploy() 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:

from ape import Contract, accounts, networks, project

account = 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 Interaction

After you have deployed your contracts, you can begin interacting with them. deploy methods return a contract instance from which you can call methods on:

from ape import project

contract = project.MyContract.deploy(sender=account)

# Interact with deployed contract
receipt = 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_value

Include a sender to delegate the transaction to an account contract:

from ape import accounts

account = 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])

Testing

Accounts

You can use starknet-devnet accounts in your tests.

import pytest
import ape


@pytest.fixture
def devnet_accounts():
    return ape.accounts.containers["starknet"].test_accounts


@pytest.fixture
def owner(devnet_accounts):
    return devnet_accounts[0]

Additionally, any accounts deployed in the local network are not saved to disk and are ephemeral.

import pytest
import ape


@pytest.fixture(scope="session")
def ephemeral_account():
    accounts = ape.accounts.containers["starknet"]
    accounts.deploy_account("ALIAS")

    # This account only exists in the devnet and is not a key-file account.
    return accounts.load("ALIAS")

Paying Fees

Starknet fees are currently paid in ETH, which is an ERC-20 on the Starknet chain. To check your account balance (in ETH), use the balance property on the account:

from ape import accounts

acct = 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 the max_fee kwarg on an invoke-transaction:

receipt = contract.my_mutable_method(123, max_fee=2900000000000)

NOTE: By not setting the max_fee, it will automatically get set to the value returned from the provider estimate_gas_cost() call. You do not need to call estimate_gas_cost() explicitly.

Mainnet Alpha Whitelist Deployment Token

Currently, 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:

from ape import project

my_contract = project.MyContract.deploy(token="MY_TOKEN")

Via an Environment Variable:

export ALPHA_MAINNET_WL_DEPLOY_TOKEN="MY_TOKEN"

Or, via the --token flag when deploying an account:

ape starknet accounts create MY_ACCOUNT --token MY_TOKEN

Development

This 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ape-starknet-0.5.0a5.tar.gz (108.9 kB view details)

Uploaded Source

Built Distribution

ape_starknet-0.5.0a5-py3-none-any.whl (45.8 kB view details)

Uploaded Python 3

File details

Details for the file ape-starknet-0.5.0a5.tar.gz.

File metadata

  • Download URL: ape-starknet-0.5.0a5.tar.gz
  • Upload date:
  • Size: 108.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.16

File hashes

Hashes for ape-starknet-0.5.0a5.tar.gz
Algorithm Hash digest
SHA256 1d967d061a0efe4f9f9cf22d60b60f6a84e86fbfe2d3ba1357280df84af08cda
MD5 99239c60e3b9842976160da1294a8ca7
BLAKE2b-256 d64b919a6d7dc28f42453cb2917ffc70801e003c59005e218d8e686631a82c5a

See more details on using hashes here.

File details

Details for the file ape_starknet-0.5.0a5-py3-none-any.whl.

File metadata

File hashes

Hashes for ape_starknet-0.5.0a5-py3-none-any.whl
Algorithm Hash digest
SHA256 56baf32a7b72ea5b9232cee991d95ede73d3effe066a08f55bc55d87ca09385f
MD5 c49fb4faa986f3995a87bc3be1a44570
BLAKE2b-256 bc8f182849a6820c44e7bdc7bf87af4eb1cc93a8a83cbdfe8d9c77a1d92dfaba

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page