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

Try to lighten the test process. #5

Merged
merged 31 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b32630d
feat: implement new test structure.
clement-ux Jul 19, 2024
98cc829
fix: remove previous test structure.
clement-ux Jul 19, 2024
efc9976
build: fix CI.
clement-ux Jul 19, 2024
e82e2bb
fix: import missing file.
clement-ux Jul 19, 2024
55fecc6
fix: import path.
clement-ux Jul 19, 2024
92997d5
forge fmt
clement-ux Jul 19, 2024
a7d9afb
build: improve CI.
clement-ux Jul 19, 2024
01042b9
feat: decoupling deployment script from test.
clement-ux Jul 19, 2024
c09e849
chore: add verbosity on `.toml`.
clement-ux Jul 19, 2024
ef043d5
feat: improve deployment script.
clement-ux Jul 19, 2024
0c6ac01
chore: add a Makefile.
clement-ux Jul 19, 2024
2dcbae8
chore: add `.env` example.
clement-ux Jul 19, 2024
7662f58
[WIP]: add PoC for tasks in Solidity.
clement-ux Jul 19, 2024
6e8b01a
fix import
clement-ux Jul 19, 2024
518fbde
chore: add all broadcast files to `.gitignore`.
clement-ux Jul 20, 2024
b011a4c
fix: swap task.
clement-ux Jul 20, 2024
b6f4df6
fix: improve deployment file.
clement-ux Jul 20, 2024
7ed9fda
feat: add new rules for deployment and task.
clement-ux Jul 20, 2024
f049fe4
apply fmt
clement-ux Jul 20, 2024
381f2db
docs: add description to contracts pupose.
clement-ux Jul 22, 2024
97c0d28
feat: implement asOwner modifier.
clement-ux Jul 22, 2024
71a09e6
feat: add helper and modifier to Shared tests.
clement-ux Jul 22, 2024
bec9702
feat: add mockCall library.
clement-ux Jul 22, 2024
41cb370
feat: update readme.
clement-ux Jul 22, 2024
9939959
test: match test with current deployed contract on virtual testnet.
clement-ux Jul 29, 2024
7189351
Prettier README
naddison36 Jul 30, 2024
cba43e7
Fix typos
naddison36 Jul 30, 2024
4bb9015
Updated README
naddison36 Jul 30, 2024
02e9f5f
Add gas command for gas usage report
naddison36 Jul 30, 2024
09439b5
Restore DeployManager
naddison36 Jul 30, 2024
185b04f
WIP add DeployManager to Shared tests
naddison36 Jul 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
### Providers URL ###
PROVIDER_URL= # [MANDATORY] : URL Provider for mainnet forks.

### Etherscan ###
# ETHERSCAN_API_KEY= # [OPTIONAL] : API Key for Etherscan. Useful for verifying contracts and reading logs on forks.

### Deployer ###
# DEPLOYER_PRIVATE_KEY= # [OPTIONAL] : Private key of the deployer. Mandatory only for deploying contracts.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ jobs:
uses: foundry-rs/foundry-toolchain@v1

- name: Run fork tests
run: forge test --fork-url $PROVIDER_URL -vvv
run: forge test -vvv --summary --detailed
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ bin/
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/
broadcast
logs

# Dotenv file
Expand All @@ -21,6 +22,10 @@ yarn.lock
cache_hardhat
artifacts

# Forge
.gas-snapshot
build/

# Defender Actions
dist

Expand Down
57 changes: 57 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
-include .env

.EXPORT_ALL_VARIABLES:
MAKEFLAGS += --no-print-directory

default:
forge fmt && forge build

# Always keep Forge up to date
install:
foundryup
forge install

gas:
@forge test --gas-report

# Generate gas snapshots for all your test functions
snapshot:
@forge snapshot

# Tests
test:
@forge test --summary

test-f-%:
@FOUNDRY_MATCH_TEST=$* make test

test-c-%:
@FOUNDRY_MATCH_CONTRACT=$* make test

# Coverage
coverage:
@forge coverage --report lcov
@lcov --ignore-errors unused --remove ./lcov.info -o ./lcov.info.pruned "test/*" "script/*"

coverage-html:
@make coverage
@genhtml ./lcov.info.pruned -o report --branch-coverage --output-dir ./coverage

# Deploy contract
simulate-c-%:
@forge script script/$*.s.sol --fork-url $(PROVIDER_URL) -vvvvv

deploy-c-%:
@forge script script/$*.s.sol --rpc-url $(PROVIDER_URL) --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --slow --verify -vvvvv

# Tasks
simulate-t-swap:
forge clean
forge script script/999_Tasks.s.sol --fork-url $(PROVIDER_URL) -vvvvv -s "swap(address,address,uint256)" $(FROM) $(TO) $(AMOUNT)

run-t-swap:
forge clean
forge script script/999_Tasks.s.sol --rpc-url $(PROVIDER_URL) --private-key ${DEPLOYER_PRIVATE_KEY} --broadcast --slow --verify -vvvvv -s "swap(address,address,uint256)" $(FROM) $(TO) $(AMOUNT)

# Override default `test` and `coverage` targets
.PHONY: test coverage
80 changes: 72 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,48 @@ Swap OETH for WETH at 1:1 ratio.
foundryup
forge install
forge compile
cp .env.example .env
```

In the `.env` file, set the environment variables as needed. eg `PROVIDER_URL` for the RPC endpoint.

### Running tests

Fork and Unit tests run with the same command, as the fork is initiated on the test file itself if needed.

By default:

- verbosity is set to 3, i.e. are displayed logs, assertion errors (expected vs actual), and stack traces for failing tests.
- a summary of the test is displayed at the end.

To run all tests:

```
make test
```

To run only a test contract:

```
make test-c-TestContractName
```

To run only a specific test

### Running gas report scripts
```
make test-f-TestFunctionName
```

Report gas usage for tests:

```
make gas
```

## Open Zeppelin Defender

[Open Zeppelin Defender v2](https://docs.openzeppelin.com/defender/v2/) is used to manage the Operations account and automate AMM operational jobs like managing liquidity.


### Deploying Defender Autotasks

Autotasks are used to run operational jobs are specific times or intervals.
Expand Down Expand Up @@ -54,15 +84,49 @@ The following will upload the different Autotask bundles to Defender.

`rollup` and `defender-autotask` can be installed globally to avoid the `npx` prefix.

## Script

### Testing script

- The deployment will happen on RPC used on the .env file, under `PROVIDER_URL`.
- If `DEPLOYER_PRIVATE_KEY` key exist, it will use it to simulate the deployment.
- Otherwise it will create an address for the test.

## Deployment
#### For smart contract

### Dry-run on fork
```
$ DEPLOYER_PRIVATE_KEY=$DEPLOYER_PRIVATE_KEY forge script script/deploy/DeployManager.sol:DeployManager --fork-url $ALCHEMY_PROVIDER_URL
make simulate-c-ScriptContractName
# example: make simulate-c-001_OETH_ARM
```

### Deployment with Verification
#### For task

```
make simulate-t-taskName $(ARGS1) $(ARGS2)
# example: make simulate-task-swap FROM=0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3 TO=0x0000000000000000000000000000000000000000 AMOUNT=1234
```

### Running script

The `DEPLOYER_PRIVATE_KEY` on the `.env` is mandatory here!
It will run with the following options:

- broadcast (send transaction for real)
- slow (i.e. send tx after prior confirmed and succeeded)
- verify (verify contract on Etherscan)
- max verbosity

#### For smart contract

`ETHERSCAN_API_KEY` is mandatory here!

```
make deploy-c-ScriptContractName
```

#### For task

```
make run-t-taskName $(ARGS1) $(ARGS2)
# example: make run-task-swap FROM=0x856c4Efb76C1D1AE02e20CEB03A2A6a08b0b8dC3 TO=0x0000000000000000000000000000000000000000 AMOUNT=1234
```
$ DEPLOYER_PRIVATE_KEY=$DEPLOYER_PRIVATE_KEY forge script script/deploy/DeployManager.sol:DeployManager --fork-url $ALCHEMY_PROVIDER_URL --slow --legacy --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY
```
Empty file removed build/.gitkeep
Empty file.
1 change: 0 additions & 1 deletion build/deployments.json

This file was deleted.

1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
src = "src/contracts"
out = "out"
libs = ["lib"]
verbosity = 3

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

Expand Down
56 changes: 56 additions & 0 deletions script/001_OETH_ARM.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

// Foundry
import {console} from "forge-std/console.sol";
import {Script} from "forge-std/Script.sol";

// Contracts
import {Proxy} from "contracts/Proxy.sol";
import {OEthARM} from "contracts/OethARM.sol";

// Utils
import {Mainnet} from "test/utils/Addresses.sol";

/// @notice Deploy the OEthARM contract using a proxy.
/// @dev 1. Deploy the proxy contract.
/// 2. Deploy the OEthARM implementation contract.
/// 3. Initialize the proxy contract with the OEthARM implementation contract.
contract _001_OETHARMScript is Script {
address public deployer;

//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////
function setUp() public virtual {
if (vm.envExists("DEPLOYER_PRIVATE_KEY")) {
console.log("Using real deployer address");
// Fetch PK from env and derive the deployer address
deployer = vm.addr(vm.envUint("DEPLOYER_PRIVATE_KEY"));
} else {
console.log("Using default deployer address");
// If no PK is provided, use a default deployer address
deployer = makeAddr("deployer");
}
}

//////////////////////////////////////////////////////
/// --- RUN
//////////////////////////////////////////////////////
function run() public {
// 🟡 All the next transactions will be sent by the deployer if `--broadcast`option is used on the command line 🟡
vm.startBroadcast(deployer);

// 1. Deploy proxy contracts
Proxy proxy = new Proxy();

// 2. Deploy implementation
OEthARM oethARMImple = new OEthARM();

// 3. Initialize proxy
proxy.initialize(address(oethARMImple), Mainnet.TIMELOCK, "");

// Stop broadcasting
vm.stopBroadcast();
}
}
98 changes: 98 additions & 0 deletions script/999_Tasks.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

// Foundry
import {console} from "forge-std/console.sol";
import {Script} from "forge-std/Script.sol";

// Contracts
import {OEthARM} from "contracts/OethARM.sol";

// Interfaces
import {IERC20} from "contracts/Interfaces.sol";

// Utils
import {Mainnet} from "test/utils/Addresses.sol";

contract _999_TasksScript is Script {
address public deployer;

bytes32 emptyStringHash = keccak256(abi.encodePacked(""));
//////////////////////////////////////////////////////
/// --- SETUP
//////////////////////////////////////////////////////

function setUp() public {
if (vm.envExists("DEPLOYER_PRIVATE_KEY")) {
console.log("Deployer private key found in env");
// Fetch PK from env and derive the deployer address
deployer = vm.addr(vm.envUint("DEPLOYER_PRIVATE_KEY"));
} else {
// If no PK is provided, use a default deployer address
deployer = makeAddr("deployer");
}
}

//////////////////////////////////////////////////////
/// --- TASKS
//////////////////////////////////////////////////////
function swap(address from, address to, uint256 amount) public {
vm.startBroadcast(deployer);

if (from != address(0) && to != address(0)) {
revert("Cannot specify both from and to asset. It has to be one or the other");
}

if (from != address(0)) {
require(from == Mainnet.OETH || from == Mainnet.WETH, "Invalid from asset");

to = from == Mainnet.OETH ? Mainnet.WETH : Mainnet.OETH;

string memory message = string(
abi.encodePacked(
"About to swap ",
vm.toString(amount),
" ",
vm.toString(from),
" to ",
vm.toString(to),
" for ",
vm.toString(deployer)
)
);

console.log(message);

// Execute the swap
OEthARM(Mainnet.OETHARM).swapExactTokensForTokens(IERC20(from), IERC20(to), amount, 0, deployer);
} else if (to != address(0)) {
require(to == Mainnet.OETH || to == Mainnet.WETH, "Invalid to asset");

from = to == Mainnet.OETH ? Mainnet.WETH : Mainnet.OETH;

string memory message = string(
abi.encodePacked(
"About to swap ",
vm.toString(from),
" to ",
vm.toString(amount),
" ",
vm.toString(to),
" for ",
vm.toString(deployer)
)
);

console.log(message);

// Execute the swap
OEthARM(Mainnet.OETHARM).swapTokensForExactTokens(
IERC20(from), IERC20(to), amount, type(uint256).max, deployer
);
} else {
revert("Must specify either from or to asset");
}

vm.stopBroadcast();
}
}
3 changes: 0 additions & 3 deletions script/deploy/mainnet/BaseMainnetScript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ abstract contract BaseMainnetScript is Script {
function setUp() external {}

function run() external {
if (block.chainid != 1) {
revert("Not Mainnet");
}
// Will not execute script if after this block number
if (block.number > deployBlockNum) {
// console.log("Current block %s, script block %s", block.number, deployBlockNum);
Expand Down
Loading