Skip to content

Commit

Permalink
Fixed and update brownie test files
Browse files Browse the repository at this point in the history
  • Loading branch information
0x-stan committed Apr 13, 2022
1 parent e4809c7 commit 8696db0
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 55 deletions.
104 changes: 91 additions & 13 deletions basic/19-brownie/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Brownie 的使用
# Brownie

本项目使用 Brownie 来运行 uniswapv1 的 test cases,基于 brownie 的特性对原有的 uniswapv1 项目
的 test 进行了重新编写,并且加入了详细的注释
Brownie 是一个基于 Python 针对以太坊虚拟机的智能合约的开发和测试框架。

## 安装 Brownie
## Brownie 的使用

使用 Brownie 来运行 uniswapv1 的 test cases,基于 Brownie 的特性对原有的 uniswapv1 项目的 test 进行了重新编写,并且加入了详细的注释

### 安装 Brownie

- 安装依赖 Brownie

Expand Down Expand Up @@ -40,39 +43,114 @@ Type 'brownie <command> --help' for specific options and more information abo
each command.
```

## 安装 Ganache
### Interacting with your Contracts

brownie 调试控制台,可以和链上合约进行交互操作

```sh
npm install -g ganache-cli
cd ./brownie_test
brownie console
```

## 启动 Ganache
brownie 会自动编译合约,并启动一个内置的 Ganache 本地测试网络,最后提供一个可实时交互的控制台

开启单独的一个窗口, 在其中启动 Ganache
```sh
accounts[0]
# <Account '0x66aB6D9362d4F35596279692F0251Db635165871'>
```

我们尝试直接在控制部署一个 ERC20 token,并进行简单的交互

```sh
ganache-cli
my_token = SimpleToken.deploy("DappLearning", "DL", 18, 0, {"from": accounts[0]})

# Transaction sent: 0x85f8c323e312cb49384eac81172de9bd54901a68d28263e22c3f4689af14d197
# Gas price: 0.0 gwei Gas limit: 12000000 Nonce: 0
# SimpleToken.constructor confirmed - Block: 1 Gas used: 1843102 (15.36%)
# SimpleToken deployed at: 0x3194cBDC3dbcd3E11a07892e7bA5c3394048Cc87
```

## 编译合约
my_token 将缓存部署的token合约对象,我们来尝试进行交互

```sh
tx1=my_token.mint(accounts[0].address, 1000000*10**18, {'from': accounts[0]})
# Transaction sent: 0xcdd7...

tx1.events
# {'Transfer': [OrderedDict([('from', '0x0000000000000000000000000000000000000000'), ('to', '0x66aB6D9362d4F35596279692F0251Db635165871'), ('value', 1000000000000000000000000)])]}

history[-1]==tx1
# True

my_token.balanceOf(accounts[0].address)
# 1000000000000000000000000
```

### 编译合约

```sh
cd brownie_test
brownie compile
```

## 测试合约
### 测试合约

```
```sh
brownie test
```

## 执行脚本
### 执行脚本

```sh
brownie run *.py --network kovan
```

## pytest

Brownie 推荐使用 pytest 编写测试案例。

- [pytest documents](https://docs.pytest.org/en/latest/)

### Brownie Pytest Fixtures

Fixtures 是 pytest 应用于一个或多个测试函数的函数,并在执行每个测试之前被调用。Fixtures 用于设置测试所需的初始条件。

Brownie 提供了简化与项目交互和测试的 Fixtures。大多数核心功能可以通过 Fixures 而不是 import 语句来访问。例如,这是前面使用 Brownie 固定装置而不是 import 的示例:

```python
import pytest

@pytest.fixture
def token(Token, accounts):
return accounts[0].deploy(Token, "Dapp-Learning", "DL", 18, 1000)

def test_transfer(token, accounts):
token.transfer(accounts[1], 100, {'from': accounts[0]})
assert token.balanceOf(accounts[0]) == 900
```

### conftest.py

我们可以把通用的 Fixuters 函数放到 `conftest.py` 文件中,pytest 测试框架会在每个测试案例开始之前,自动加载器中的 Fixtures。

```python
# ./conftest.py

@pytest.fixture
def DL_token():
SimpleToken.deploy("Dapp-Learning", "DL", 18, 0, {"from": accounts[0]})
...
```

```python
# ./test_eth_to_token.py

def test_eth_to_token_swap(DL_token):
DL_token.approve(some_address, 10 * 10**18, {"from": accounts[0]})
...
```


## 参考链接

- brownie 官网: <https://eth-brownie.readthedocs.io/en/stable/toctree.html>
Expand Down
67 changes: 67 additions & 0 deletions basic/19-brownie/brownie_test/brwonie-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Brownie Configuration File
project_structure:
build: build
contracts: contracts
interfaces: interfaces
reports: reports
scripts: scripts
tests: tests

networks:
default: development
development:
gas_limit: max
gas_buffer: 1
gas_price: 0
max_fee: null
priority_fee: null
reverting_tx_gas_limit: max
default_contract_owner: true
cmd_settings: null
live:
gas_limit: auto
gas_buffer: 1.1
gas_price: auto
max_fee: null
priority_fee: null
reverting_tx_gas_limit: false
default_contract_owner: false

compiler:
evm_version: null
solc:
version: null
optimizer:
enabled: true
runs: 200
remappings: null
vyper:
version: null

console:
show_colors: true
color_style: monokai
auto_suggest: true
completions: true
editing_mode: emacs

reports:
exclude_paths: null
exclude_contracts: null
only_include_project: true

hypothesis:
deadline: null
max_examples: 50
report_multiple_bugs: False
stateful_step_count: 10
phases:
explicit: true
reuse: true
generate: true
target: true
shrink: true

autofetch_sources: false
dependencies: null
dev_deployment_artifacts: false
11 changes: 0 additions & 11 deletions basic/19-brownie/brownie_test/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import pytest
from web3 import Web3
from web3.contract import ConciseContract
from brownie import SimpleToken, UniswapFactory, accounts, Contract, UniswapExchange

# reference to .
# https://github.com/Uniswap/uniswap-v1/blob/master/tests/conftest.py
# brownie made the contract deploying thing easier but hard to understand

@pytest.fixture
def w3():
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))
# w3.eth.setGasPriceStrategy(lambda web3, params: 0)
# w3.eth.defaultAccount = w3.eth.accounts[0]
# print(w3.eth.default_account)
return w3


@pytest.fixture
def HAY_token():
t = SimpleToken.deploy("HAYAHEI", "HAY", 18, 0, {"from": accounts[0]})
Expand Down
21 changes: 10 additions & 11 deletions basic/19-brownie/brownie_test/tests/exchange/test_eth_to_token.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from brownie import accounts
import brownie
from brownie import (accounts, web3)


def test_eth_to_token_swap(w3, HAY_token, hay_token_exchange):
def test_eth_to_token_swap(HAY_token, hay_token_exchange):
HAY_token.approve(hay_token_exchange, 10 * 10**18, {"from": accounts[0]})

# step 1: initialize exchange
hay_token_exchange.initializeExchange(10 * 10**18, {"from": accounts[0], "amount": 5 * 10**18})

# the swap function needs a timeout parameter
timeout = w3.eth.getBlock(w3.eth.blockNumber).timestamp + 300
timeout = web3.eth.getBlock(web3.eth.blockNumber).timestamp + 300
assert HAY_token.balanceOf(accounts[2]) == 0

hay_token_exchange.ethToTokenSwap(1, timeout, {"from": accounts[2], "amount": 1 * 10**18})
Expand All @@ -27,41 +26,41 @@ def test_eth_to_token_swap(w3, HAY_token, hay_token_exchange):
# Token Pool = 8336112037345781927
# ETH pool = 6 * 10**18
assert hay_token_exchange.ethPool() == 6 * 10**18
assert w3.eth.get_balance(hay_token_exchange.address) == 6 * 10**18
assert web3.eth.getBalance(hay_token_exchange.address) == 6 * 10**18
assert hay_token_exchange.tokenPool() == 8336112037345781927
assert HAY_token.balanceOf(hay_token_exchange) == 8336112037345781927
assert hay_token_exchange.invariant() == 50016672224074691562000000000000000000
assert HAY_token.balanceOf(accounts[2]) == 1663887962654218073


def test_fallback_eth_to_token_swap(w3, HAY_token, hay_token_exchange):
def test_fallback_eth_to_token_swap(HAY_token, hay_token_exchange):
# 测试uniswap exchange合约的默认fallback函数,即直接往这个地址转入eth,则默认是用ETH换取TOKEN的操作
HAY_token.approve(hay_token_exchange, 10 * 10**18, {"from": accounts[0]})

# step 1: initialize exchange
hay_token_exchange.initializeExchange(10 * 10**18, {"from": accounts[0], "amount": 5 * 10**18})
timeout = w3.eth.getBlock(w3.eth.blockNumber).timestamp + 300
timeout = web3.eth.getBlock(web3.eth.blockNumber).timestamp + 300

# step 2: use accounts[2] to do the test
assert HAY_token.balanceOf(accounts[2]) == 0
accounts[2].transfer(hay_token_exchange, 1 * 10**18)

assert hay_token_exchange.ethPool() == 6 * 10 ** 18
assert w3.eth.get_balance(hay_token_exchange.address) == 6 * 10 ** 18
assert web3.eth.getBalance(hay_token_exchange.address) == 6 * 10 ** 18
assert hay_token_exchange.tokenPool() == 8336112037345781927
assert HAY_token.balanceOf(hay_token_exchange) == 8336112037345781927
assert hay_token_exchange.invariant() == 50016672224074691562000000000000000000
assert HAY_token.balanceOf(accounts[2]) == 1663887962654218073


def test_eth_to_token_payment(w3, HAY_token, hay_token_exchange):
def test_eth_to_token_payment(HAY_token, hay_token_exchange):
# 测试eth2token payment函数,与swap函数不同的点是receipt是另一个地址
# 用accounts[2]的ETH取exchange中交易,交易所得TOken发往accounts[3]
HAY_token.approve(hay_token_exchange, 10 * 10 ** 18, {"from": accounts[0]})

# step 1: initialize exchange
hay_token_exchange.initializeExchange(10 * 10 ** 18, {"from": accounts[0], "amount": 5 * 10 ** 18})
timeout = w3.eth.getBlock(w3.eth.blockNumber).timestamp + 300
timeout = web3.eth.getBlock(web3.eth.blockNumber).timestamp + 300

# 开始的两个地址的TOken数量都为0
assert HAY_token.balanceOf(accounts[2]) == 0
Expand All @@ -70,7 +69,7 @@ def test_eth_to_token_payment(w3, HAY_token, hay_token_exchange):
hay_token_exchange.ethToTokenPayment(1, timeout, accounts[3], {"from": accounts[2], "amount": 1 * 10**18})

assert hay_token_exchange.ethPool() == 6 * 10 ** 18
assert w3.eth.get_balance(hay_token_exchange.address) == 6 * 10 ** 18
assert web3.eth.getBalance(hay_token_exchange.address) == 6 * 10 ** 18
assert hay_token_exchange.tokenPool() == 8336112037345781927
assert HAY_token.balanceOf(hay_token_exchange) == 8336112037345781927
assert hay_token_exchange.invariant() == 50016672224074691562000000000000000000
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from brownie import accounts, UniswapExchange, Contract

def test_factory(w3, HAY_token, BEE_token, uniswap_factory):
def test_factory(HAY_token, BEE_token, uniswap_factory):
assert uniswap_factory.getExchangeCount() == 0

# brownie中Contract调用transact方法时返回的是receipt,需要使用return_value来获取值
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from brownie import accounts
from brownie import (accounts, web3)
import brownie


Expand Down
2 changes: 1 addition & 1 deletion basic/19-brownie/brownie_test/tests/exchange/test_token.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from brownie import accounts
from brownie import (accounts, web3)


def test_initial_state(HAY_token):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from brownie import accounts
import brownie
from brownie import (accounts, web3)


def test_token_to_eth_swap(w3, HAY_token, hay_token_exchange):
def test_token_to_eth_swap(HAY_token, hay_token_exchange):
HAY_token.approve(hay_token_exchange, 10 * 10 ** 18, {"from": accounts[0]})

# step 1: initialize exchange
hay_token_exchange.initializeExchange(10 * 10 ** 18, {"from": accounts[0], "amount": 5 * 10 ** 18})

# the swap function needs a timeout parameter
timeout = w3.eth.getBlock(w3.eth.blockNumber).timestamp + 300
timeout = web3.eth.getBlock(web3.eth.blockNumber).timestamp + 300

# step 2: 用account[1]的token来进行token 2 eth的操作
HAY_token.approve(hay_token_exchange, 2 * 10 ** 18, {"from": accounts[1]})
Expand All @@ -34,20 +33,20 @@ def test_token_to_eth_swap(w3, HAY_token, hay_token_exchange):
assert hay_token_exchange.tokenPool() == 12 * 10**18
assert HAY_token.balanceOf(hay_token_exchange) == 12 * 10**18
assert hay_token_exchange.ethPool() == 4168056018672890963
assert w3.eth.get_balance(hay_token_exchange.address) == 4168056018672890963
assert web3.eth.getBalance(hay_token_exchange.address) == 4168056018672890963
assert hay_token_exchange.invariant() == 50016672224074691556000000000000000000
assert accounts[1].balance() == account1_eth_balance + 831943981327109037
assert HAY_token.balanceOf(accounts[1]) == 498 * 10**18


def test_token_to_eth_payment(w3, HAY_token, hay_token_exchange):
def test_token_to_eth_payment(HAY_token, hay_token_exchange):
HAY_token.approve(hay_token_exchange, 10 * 10 ** 18, {"from": accounts[0]})

# step 1: initialize exchange
hay_token_exchange.initializeExchange(10 * 10 ** 18, {"from": accounts[0], "amount": 5 * 10 ** 18})

# the swap function needs a timeout parameter
timeout = w3.eth.getBlock(w3.eth.blockNumber).timestamp + 300
timeout = web3.eth.getBlock(web3.eth.blockNumber).timestamp + 300

# step 2: 用account[1]的token来进行token 2 eth的操作, receipt为account[2]
HAY_token.approve(hay_token_exchange, 2 * 10 ** 18, {"from": accounts[1]})
Expand All @@ -62,7 +61,7 @@ def test_token_to_eth_payment(w3, HAY_token, hay_token_exchange):
assert hay_token_exchange.tokenPool() == 12 * 10 ** 18
assert HAY_token.balanceOf(hay_token_exchange) == 12 * 10 ** 18
assert hay_token_exchange.ethPool() == 4168056018672890963
assert w3.eth.get_balance(hay_token_exchange.address) == 4168056018672890963
assert web3.eth.getBalance(hay_token_exchange.address) == 4168056018672890963
assert hay_token_exchange.invariant() == 50016672224074691556000000000000000000
assert accounts[2].balance() == account2_eth_balance + 831943981327109037
assert HAY_token.balanceOf(accounts[1]) == 498 * 10 ** 18
Loading

0 comments on commit 8696db0

Please sign in to comment.