Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: issue where repr on test accounts manager was misleading #981

Merged
merged 10 commits into from
Aug 17, 2022
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:maxdepth: 1

userguides/quickstart
userguides/accounts
userguides/installing_plugins
userguides/projects
userguides/compile
Expand Down
107 changes: 107 additions & 0 deletions docs/userguides/accounts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Accounts

Accounts in Ape come from [AccountAPI](../methoddocs/api.html#ape.api.accounts.AccountAPI) implementations (e.g. from plugins).
There are typically two types of accounts:

1. Test accounts
2. Live network accounts

Test accounts are useful for local network testing and debugging contracts.
Live network accounts are for interacting with live blockchains and should be secured.

To learn more about Ethereum accounts, see [the Ethereum documentation](https://ethereum.org/en/developers/docs/accounts/).

## Test Accounts

Ape ships with pytest fixtures to assist in writing your tests.
Pre-funded test accounts are accessible via the [accounts fixture](./testing.html#accounts-fixture).

```python
def test_my_contract_method(accounts):
sender = accounts[0]
...
```

To access the same prefunded accounts in your scripts or console, use the root `accounts` object and the [test_accounts](../methoddocs/managers.html#ape.managers.accounts.AccountManager.test_accounts) property:

```python
from ape import accounts

sender = accounts.test_accounts[0]
```

You can configure your test accounts using your `ape-config.yaml` file:

```yaml
test:
mnemonic: test test test test test test test test test test test junk
number_of_accounts: 5
```

antazoey marked this conversation as resolved.
Show resolved Hide resolved
**WARN**: NEVER put a seed phrase with real funds here.
The accounts generated from this seed are solely for testing and debugging purposes.

Learn more about test accounts from the [testing guide](./testing.html#accounts-fixture).

## Live Network Accounts

When using live networks, you need to get your accounts into Ape.
Ape ships with a keyfile accounts plugin to assist with this.
All the available CLI commands for this accounts plugin can be found [here](../commands/accounts.html).

For example, you can [generate](../commands/accounts.html#accounts-generate) an account:

```bash
ape accounts generate <ALIAS>
```

It will prompt you for a passphrase.

If you already have an account and you wish to import it into Ape (say, from Metamask), you can use the [import command](../commands/accounts.html#accounts-import):

```bash
ape accounts import <ALIAS>
```

It will prompt you for the private key.
If you need help exporting your private key from Metamask, see [this guide](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key).

Then, in your scripts, you can [load](../methoddocs/managers.html#ape.managers.accounts.AccountManager.load) an account:

```python
from ape import accounts

account = accounts.load("<ALIAS>")
```

## Automation

If you use your keyfile accounts in automation, such as CI/CD, you may need to programmatically unlock them and enable autosign.
antazoey marked this conversation as resolved.
Show resolved Hide resolved
**WARNING**: We don't recommend using this approach but it is possible due to sometimes being needed.
Ensure you are using a secure environment and are aware of what you are doing.

```python
from ape import accounts
from eth_account.messages import encode_defunct

account = accounts.load("<ALIAS>")
account.set_autosign(True, passphrase="<PASSPHRASE>")

# Now, you will not be prompted to sign messages or transactions
message = encode_defunct(text="Hello Apes!")
signature = account.sign_message(message)
```

## Hardware Wallets

Because of the plugin system in Ape, we are able to support other types of accounts including hardware wallet accounts.
Check out these plugins:

* [ape-ledger](https://github.com/ApeWorX/ape-ledger)
* [ape-trezor](https://github.com/ApeWorX/ape-trezor)

To install one of these plugins, do the following:

```bash
ape plugins install ledger
```
38 changes: 18 additions & 20 deletions docs/userguides/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ Testing an ape project is important and easy.

## Test Structure

Tests must be located in a project's `tests/` directory. Each **test file** must start with `test_` and have the `.py`
extension, such as `test_my_contract.py`. Each **test method** within the file must also start with `test_`. The following
is an example test:
Tests must be located in a project's `tests/` directory. Each **test file** must start with `test_` and have the `.py` extension, such as `test_my_contract.py`.
Each **test method** within the file must also start with `test_`.
The following is an example test:

```python
def test_add():
assert 1 + 1 == 2
```

**NOTE**: `pytest` assumes the *actual* value is on the left and the *expected* value is on the right.

## Test Pattern

Tests are generally divisible into three parts:
Expand All @@ -20,10 +23,11 @@ Tests are generally divisible into three parts:
2. Invocation
3. Assertion

In the example above, we created a fixture that deploys our smart-contract. This is an example of a 'setup' phase.
Next, we need to call a method on our contract. Let's assume there is an `authorized_method()` that requires the
owner of the contract to make the transaction. If the sender of the transaction is not the owner, the transaction
will fail to complete and will revert.
In the example above, we created a fixture that deploys our smart-contract.
This is an example of a 'setup' phase.
Next, we need to call a method on our contract.
Let's assume there is an `authorized_method()` that requires the owner of the contract to make the transaction.
If the sender of the transaction is not the owner, the transaction will fail to complete and will revert.

This is an example of how that test may look:

Expand Down Expand Up @@ -57,9 +61,9 @@ with fixtures you will likely want to use:

### accounts fixture

You have access to test accounts. These accounts are automatically funded, and you can use them to transact in your
tests. Access each [test account](../methoddocs/api.html?highlight=testaccount#ape.api.accounts.TestAccountAPI) by
index from the `accounts` fixture:
You have access to test accounts.
These accounts are automatically funded, and you can use them to transact in your tests.
Access each [test account](../methoddocs/api.html?highlight=testaccount#ape.api.accounts.TestAccountAPI) by index from the `accounts` fixture:

```python
def test_my_method(accounts):
Expand All @@ -72,7 +76,6 @@ For code readability and sustainability, create your own fixtures using the `acc
```python
import pytest


@pytest.fixture
def owner(accounts):
return accounts[0]
Expand All @@ -87,8 +90,7 @@ def test_my_method(owner, receiver):
...
```

You can configure your accounts by changing the `mnemonic` or `number_of_accounts` settings in the `test` section of
your `ape-config.yaml` file:
You can configure your accounts by changing the `mnemonic` or `number_of_accounts` settings in the `test` section of your `ape-config.yaml` file:

```yaml
test:
Expand All @@ -113,8 +115,7 @@ def test_my_method(project, accounts):
contract.my_method(sender=other_contract)
```

It has the same interface as the [TestAccountManager](../methoddocs/managers.html#ape.managers.accounts.TestAccountManager),
(same as doing `accounts.test_accounts` in a script or the console).
It has the same interface as the [TestAccountManager](../methoddocs/managers.html#ape.managers.accounts.TestAccountManager), (same as doing `accounts.test_accounts` in a script or the console).

### chain fixture

Expand Down Expand Up @@ -188,18 +189,15 @@ ape test test_my_contract -I -s

## Test Providers

Out-of-the-box, your tests run using the `eth-tester` provider, which comes bundled with ape. If you have `geth`
installed, you can use the `ape-geth` plugin that also comes with ape.
Out-of-the-box, your tests run using the `eth-tester` provider, which comes bundled with ape. If you have `geth` installed, you can use the `ape-geth` plugin that also comes with ape.

```bash
ape test --network ethereum:local:geth
```

Each testing plugin should work the same way. You will have access to the same test accounts.

Another option for testing providers is the [ape-hardhat plugin](https://github.com/ApeWorX/ape-hardhat), which does
not come with `ape` but can be installed by including it in the `plugins` list in your `ape-config.yaml` file or
manually installing it using the command:
Another option for testing providers is the [ape-hardhat plugin](https://github.com/ApeWorX/ape-hardhat), which does not come with `ape` but can be installed by including it in the `plugins` list in your `ape-config.yaml` file or manually installing it using the command:

```bash
ape plugins install hardhat
Expand Down
4 changes: 4 additions & 0 deletions src/ape/managers/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
class TestAccountManager(list, ManagerAccessMixin):
__test__ = False

def __repr__(self) -> str:
accounts_str = ", ".join([a.address for a in self.accounts])
return f"[{accounts_str}]"

@property
def containers(self) -> Dict[str, TestAccountContainerAPI]:
containers = {}
Expand Down
5 changes: 5 additions & 0 deletions tests/functional/test_accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,8 @@ def test_custom_num_of_test_accts_config(test_accounts, temp_config):

with temp_config(test_config):
assert len(test_accounts) == CUSTOM_NUMBER_OF_TEST_ACCOUNTS


def test_test_accounts_repr(test_accounts):
actual = repr(test_accounts)
assert all(a.address in actual for a in test_accounts)