Skip to content

Commit

Permalink
Dockerize anvil; forge scripts for deploying seaport, valorem, mock c…
Browse files Browse the repository at this point in the history
…ontracts (#50)

* add anvil script

* update gitignore

* ignore anvil files

* chore: forge init

* forge install: forge-std

v1.5.3

* forge install: seaport

* forge install: seaport-order-validator

v0.1.1

* forge install: valorem-core

v1.0.0

* drop init foundry files

* add forge scripts for seaport and valorem init

* add remappings file

* drop foundry boilerplate

* update readme w anvil info + addresses

* drop seaport init script; add script for initializing valorem options

* bugfixes for init scripts

* add mock erc20 mint, approval, options write

* forge install: solmate

* preapprove seaport for spending valorem 1155s

* refac; init order struct

* create and validate seaport order

* fix gitmodules merge

* feedback: drop usdc, weth, uni; use mocks

* drop solmate

* feedback: drop unnecessary cast

* feedback: udpate readme
  • Loading branch information
Flip-Liquid authored Apr 26, 2023
1 parent 3761aed commit 3618de2
Show file tree
Hide file tree
Showing 11 changed files with 284 additions and 3 deletions.
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
/target
.idea
.env
.vscode

broadcast/
cache/
out/

# Local settings file - if stored under the repository
settings.toml
settings.toml
12 changes: 12 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[submodule "proto"]
path = proto
url = [email protected]:valorem-labs-inc/exchange-proto.git
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/seaport"]
path = lib/seaport
url = https://github.com/ProjectOpenSea/seaport
[submodule "lib/seaport-order-validator"]
path = lib/seaport-order-validator
url = https://github.com/ProjectOpenSea/seaport-order-validator
[submodule "lib/valorem-core"]
path = lib/valorem-core
url = https://github.com/valorem-labs-inc/valorem-core
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,10 @@ at application startup.
### Local development environment

Developers will need rust and docker to work on this project. Docker is used
to host a local instance of the postgres database to execute tests against.
To set up a local database, run: `./scripts/init_db.sh` and `./scripts/init_redis.sh`
to host a local instance of the postgres database, redis instance, and anvil testnet node to execute tests against.
To set these up, run: `./scripts/init_db.sh`, `./scripts/init_redis.sh`, and `./scripts/init_anvil.sh`.

Note: when running `init_anvil.sh`, an enviroment variable `FORK_RPC_URL` in the format `<URL>@<BLOCK NO>` should be supplied for the `anvil -f` command. This will fork the specified chain at the block number supplied. The tests in `tests/api` are written against a fork of the Arbitrum Goerli chain @ block 17333455.

#### Building the project

Expand All @@ -112,6 +114,16 @@ Tests live in the `/tests` folder.

#### Running the tests

The tests in tests/api/ are a set of integration tests that use dockerized instances of redis, Postgres, and anvil. The tests simulate on-chain interactions against a forked testnet hosted in the anvil docker container. The fork used for the anvil testnet is from Arbitrum Goerli at block no. 17333455.

Below are the relevant addresses used in testing:

| Contract | Address |
|---------------------|----------------------------------------------|
| Seaport 1.1 | `0x00000000006c3852cbEf3e08E8dF289169EdE581` |
| Seaport validator | `0xF75194740067D6E4000000003b350688DD770000` |
| Valorem Clearinghouse 1.0 | `0x7513F78472606625A9B505912e3C80762f6C9Efb` |

Run `cargo test` any time after setting up your development environment.

## CI/CD
Expand Down
6 changes: 6 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
1 change: 1 addition & 0 deletions lib/forge-std
Submodule forge-std added at fc560f
1 change: 1 addition & 0 deletions lib/seaport
Submodule seaport added at b13939
1 change: 1 addition & 0 deletions lib/seaport-order-validator
1 change: 1 addition & 0 deletions lib/valorem-core
Submodule valorem-core added at 0252a9
5 changes: 5 additions & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ds-test/=lib/forge-std/lib/ds-test/src/
forge-std/=lib/forge-std/src/
seaport/=lib/seaport/
seaport-validator/=lib/seaport-order-validator/
valorem-core/=lib/valorem-core/
200 changes: 200 additions & 0 deletions scripts/forge/InitValoremClearinghouseOptions.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Script.sol";
import {IERC20} from "forge-std/interfaces/IERC20.sol";
import { ConsiderationInterface } from "seaport/contracts/interfaces/ConsiderationInterface.sol";
import "seaport/contracts/lib/ConsiderationStructs.sol";

import { ValoremOptionsClearinghouse } from "valorem-core/src/ValoremOptionsClearinghouse.sol";
import { MockERC20 } from "valorem-core/test/utils/MockERC20.sol";

contract InitValoremClearinghouseOptionsScript is Script {
address public constant SEAPORT_A = 0x00000000006c3852cbEf3e08E8dF289169EdE581;
address public constant SEAPORT_VALIDATOR_A = 0xF75194740067D6E4000000003b350688DD770000;
address public constant CLEARINGHOUSE_A = 0x7513F78472606625A9B505912e3C80762f6C9Efb;

MockERC20 public MOCK_VOL_1;
MockERC20 public MOCK_STABLE;
MockERC20 public MOCK_VOL_2;

// TODO extract this and pk to .env var
// address corresponding to anvil dev account
// NOTE: this is also expected to be the sender of each transaction in this script,
// and --from should be supplied to the forge script invocation
address payable public constant ORDERER_A = payable(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266);
uint256 public constant ORDERER_PK = 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80;

uint256 public WETH_USDC_1M_ID;
uint256 public UNI_USDC_1M_ID;

ConsiderationInterface seaport;
ValoremOptionsClearinghouse clearinghouse;

function run() public {
vm.startBroadcast();

// verify two orders for valorem options
seaport = ConsiderationInterface(SEAPORT_A);
clearinghouse = ValoremOptionsClearinghouse(CLEARINGHOUSE_A);

mint_and_approve();
init_option_types();

uint256 weth_usdc_claim = clearinghouse.write(WETH_USDC_1M_ID, 10);
uint256 uni_usdc_claim = clearinghouse.write(UNI_USDC_1M_ID, 10);

vm.stopBroadcast();
}

function init_option_types() internal {
uint40 ts = uint40(block.timestamp);

// create options types
WETH_USDC_1M_ID = clearinghouse.newOptionType({
underlyingAsset: address(MOCK_VOL_1),
underlyingAmount: 1 ether,
exerciseAsset: address(MOCK_STABLE),
exerciseAmount: 1600 ether,
exerciseTimestamp: ts + 1 days,
expiryTimestamp: ts + 30 days
});

UNI_USDC_1M_ID = clearinghouse.newOptionType({
underlyingAsset: address(MOCK_VOL_2),
underlyingAmount: 1 ether,
exerciseAsset: address(MOCK_STABLE),
exerciseAmount: 2500 ether,
exerciseTimestamp: ts + 1 days,
expiryTimestamp: ts + 30 days
});
}

function mint_and_approve() internal {
MOCK_VOL_1 = new MockERC20("Wrapped Ether", "WETH", 18);
MOCK_VOL_2 = new MockERC20("Uniswap", "UNI", 18);
MOCK_STABLE = new MockERC20("USD Coin", "USDC", 6);

MOCK_VOL_1.mint(ORDERER_A, 1000000 ether);
MOCK_VOL_2.mint(ORDERER_A, 1000000 ether);
MOCK_STABLE.mint(ORDERER_A, 1000000 ether);

MOCK_VOL_1.approve(CLEARINGHOUSE_A, 1000000 ether);
MOCK_VOL_2.approve(CLEARINGHOUSE_A, 1000000 ether);
MOCK_STABLE.approve(CLEARINGHOUSE_A, 1000000 ether);

// preapprove seaport to transfer the NFTs
clearinghouse.setApprovalForAll(SEAPORT_A, true);
}

function init_order() internal{
uint40 ts = uint40(block.timestamp);
OfferItem[] memory offer = new OfferItem[](1);
offer[0] = OfferItem({
itemType: ItemType.ERC1155,
token: address(CLEARINGHOUSE_A),
identifierOrCriteria: WETH_USDC_1M_ID,
startAmount: 1,
endAmount: 1
});
ConsiderationItem[] memory consideration = new ConsiderationItem[](1);
consideration[0] = ConsiderationItem({
itemType: ItemType.ERC20,
token: address(MOCK_STABLE),
identifierOrCriteria: WETH_USDC_1M_ID,
startAmount: 1,
endAmount: 1,
recipient: ORDERER_A
});
// offer 10 WETH/USDC 1M options
// from https://docs.opensea.io/reference/create-an-order
OrderParameters memory weth_usdc_order_params = OrderParameters({
offerer: ORDERER_A,
zone: address(0x0), // 0x004C00500000aD104D7DBd00e3ae0A5C00560C00
offer: offer,
consideration: consideration,
orderType: OrderType.FULL_OPEN,
startTime: ts + 1,
endTime: ts + 30 days,
zoneHash: 0x0000000000000000000000000000000000000000000000000000000000000000,
salt: 0,
conduitKey: 0, // 0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000,
totalOriginalConsiderationItems: consideration.length
});
// needed to calculate signature for the order
OrderComponents memory weth_usdc_order_components = OrderComponents({
offerer: ORDERER_A,
zone: address(0x0), // 0x004C00500000aD104D7DBd00e3ae0A5C00560C00
offer: offer,
consideration: consideration,
orderType: OrderType.FULL_OPEN,
startTime: ts + 1,
endTime: ts + 30 days,
zoneHash: 0x0000000000000000000000000000000000000000000000000000000000000000,
salt: 0,
conduitKey: 0, // 0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000,
counter: seaport.getCounter(ORDERER_A)
});
bytes memory signature = signOrder(
seaport,
ORDERER_PK,
seaport.getOrderHash(weth_usdc_order_components)
);

// Validates and registers the signature of the order on seaport
Order memory order = Order(weth_usdc_order_params, signature);
Order[] memory orders = new Order[](1);
orders[0] = order;
if(!seaport.validate(orders)){
revert("invalid order");
}
}

function signOrder(
ConsiderationInterface _consideration,
uint256 _pkOfSigner,
bytes32 _orderHash
) internal view returns (bytes memory) {
(bytes32 r, bytes32 s, uint8 v) = getSignatureComponents(
_consideration,
_pkOfSigner,
_orderHash
);
return abi.encodePacked(r, s, v);
}

function signOrder2098(
ConsiderationInterface _consideration,
uint256 _pkOfSigner,
bytes32 _orderHash
) internal view returns (bytes memory) {
(bytes32 r, bytes32 s, uint8 v) = getSignatureComponents(
_consideration,
_pkOfSigner,
_orderHash
);
uint256 yParity;
if (v == 27) {
yParity = 0;
} else {
yParity = 1;
}
uint256 yParityAndS = (yParity << 255) | uint256(s);
return abi.encodePacked(r, yParityAndS);
}

function getSignatureComponents(
ConsiderationInterface _consideration,
uint256 _pkOfSigner,
bytes32 _orderHash
) internal view returns (bytes32, bytes32, uint8) {
(, bytes32 domainSeparator, ) = _consideration.information();
(uint8 v, bytes32 r, bytes32 s) = vm.sign(
_pkOfSigner,
keccak256(
abi.encodePacked(bytes2(0x1901), domainSeparator, _orderHash)
)
);
return (r, s, v);
}
}
36 changes: 36 additions & 0 deletions scripts/init_anvil.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -x
set -eo pipefail

# if a docker anvil is running, print instructions to kill it and exit
RUNNING_CONTAINER=$(docker ps --filter 'name=anvil' --format '{{.ID}}')
if [[ -n $RUNNING_CONTAINER ]]; then
echo >&2 "there is a anvil container already running, kill it with"
echo >&2 " docker kill ${RUNNING_CONTAINER}"
exit 1
fi

if [[ -z $FORK_RPC_URL ]]; then
echo >&2 "the fork URL for anvil must be defined in the environment variable FORK_RPC_URL"
exit 1
fi

echo >&2 "Running anvil with fork URL: $FORK_RPC_URL"

# Launch Anvil using Docker
docker run \
-p "8545:8545" \
-e ANVIL_IP_ADDR=0.0.0.0 \
--name "anvil_$(date '+%s')" \
-d ghcr.io/foundry-rs/foundry:latest \
"anvil -f ${FORK_RPC_URL}"

until cast age; do
>&2 echo "anvil is still unavailable - sleeping"
sleep 1
done

>&2 echo "Anvil is ready to go!"

forge script scripts/forge/InitValoremClearinghouseOptions.s.sol --broadcast --fork-url http://localhost:8545/ --private-key ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --use 0.8.16
>&2 echo "Seaport and Valorem Clearinghouse are ready to go!"

0 comments on commit 3618de2

Please sign in to comment.