Skip to content

Commit 16d48eb

Browse files
alexkeatingmds1
andauthored
Inital perpetual open router (#1)
* forge install: solmate * forge install: perp-curie-contract v2.4.5 * forge install: openzeppelin-contracts v4.8.2 * Working example * Cleanup * Update to pass linting * Update to pass linting * Add Optimism rpc url * Make changes based on feedback * Fix formatting * Remove SARIF * Add permalinks for interfaces * Fix toml * Add some natspec * Scopelint format * Convert to fallback function * Fix format * Remove unused import * Fix scopelint * Change comment * Changes based on feedback * Add receive to remove warning * Working closePosition * Update deposit * Add benchmarks * Some changes based on comments * More changes based on comments * Remove comment * style: fmt new statements * style: forge fmt * Add comments * Fix formatting * Change to internal * Change wording of comments --------- Co-authored-by: Matt Solomon <[email protected]>
1 parent b66daf2 commit 16d48eb

27 files changed

+4144
-67
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99

1010
env:
1111
FOUNDRY_PROFILE: ci
12+
OPTIMISM_RPC_URL: ${{ secrets.OPTIMISM_RPC_URL }}
1213

1314
jobs:
1415
build:
@@ -75,7 +76,7 @@ jobs:
7576
uses: zgosalvez/github-actions-report-lcov@v2
7677
with:
7778
coverage-files: ./lcov.info
78-
minimum-coverage: 100 # Set coverage threshold.
79+
minimum-coverage: 80 # Set coverage threshold.
7980

8081
lint:
8182
runs-on: ubuntu-latest
@@ -100,23 +101,3 @@ jobs:
100101
run: |
101102
scopelint --version
102103
scopelint check
103-
104-
slither-analyze:
105-
runs-on: ubuntu-latest
106-
permissions:
107-
security-events: write
108-
steps:
109-
- uses: actions/checkout@v3
110-
111-
- name: Run Slither
112-
uses: crytic/[email protected]
113-
id: slither # Required to reference this step in the next step.
114-
with:
115-
fail-on: none # Required to avoid failing the CI run regardless of findings.
116-
sarif: results.sarif
117-
slither-args: --filter-paths "./lib|./test" --exclude naming-convention
118-
119-
- name: Upload SARIF file
120-
uses: github/codeql-action/upload-sarif@v2
121-
with:
122-
sarif_file: ${{ steps.slither.outputs.sarif }}

.gitmodules

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
[submodule "lib/forge-std"]
22
path = lib/forge-std
33
url = https://github.com/foundry-rs/forge-std
4+
[submodule "lib/solmate"]
5+
path = lib/solmate
6+
url = https://github.com/transmissions11/solmate
7+
[submodule "lib/perp-curie-contract"]
8+
path = lib/perp-curie-contract
9+
url = https://github.com/perpetual-protocol/perp-curie-contract
10+
[submodule "lib/openzeppelin-contracts"]
11+
path = lib/openzeppelin-contracts
12+
url = https://github.com//OpenZeppelin/openzeppelin-contracts

broadcast/Benchmark.s.sol/10/run-1681856767.json

Lines changed: 1060 additions & 0 deletions
Large diffs are not rendered by default.

broadcast/Benchmark.s.sol/10/run-latest.json

Lines changed: 1060 additions & 0 deletions
Large diffs are not rendered by default.

broadcast/Deploy.s.sol/10/run-1681853983.json

Lines changed: 163 additions & 0 deletions
Large diffs are not rendered by default.

broadcast/Deploy.s.sol/10/run-latest.json

Lines changed: 163 additions & 0 deletions
Large diffs are not rendered by default.

foundry.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[profile.default]
2+
fs_permissions = [{ access = "read", path = "./broadcast" }]
23
optimizer = true
34
optimizer_runs = 10_000_000
45
solc_version = "0.8.16"
@@ -16,6 +17,13 @@
1617

1718
[fmt]
1819
bracket_spacing = false
20+
ignore = [
21+
"src/interface/IAccountBalance.sol",
22+
"src/lib/AccountMarket.sol",
23+
"src/interface/IClearingHouse.sol",
24+
"src/interface/IVault.sol",
25+
"src/test/interface/IDelegateApproval.sol",
26+
]
1927
int_types = "long"
2028
line_length = 100
2129
multiline_func_header = "attributes_first"
@@ -24,3 +32,9 @@
2432
single_line_statement_blocks = "single"
2533
tab_width = 2
2634
wrap_comments = true
35+
36+
# ===============================
37+
# ======== RPC Endpoints ========
38+
# ===============================
39+
[rpc_endpoints]
40+
optimism = "${OPTIMISM_RPC_URL}"

lib/openzeppelin-contracts

Submodule openzeppelin-contracts added at d00acef

lib/perp-curie-contract

Submodule perp-curie-contract added at 4e187e4

lib/solmate

Submodule solmate added at 2001af4

script/Benchmark.s.sol

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import {Script, stdJson} from "forge-std/Script.sol";
2+
import {DepositRouter} from "src/DepositRouter.sol";
3+
import {PerpetualRouterFactory} from "src/PerpetualRouterFactory.sol";
4+
import {ERC20} from "solmate/tokens/ERC20.sol";
5+
import {IVault} from "src/interface/IVault.sol";
6+
import {IClearingHouse} from "src/interface/IClearingHouse.sol";
7+
import {IDelegateApproval} from "test/interface/IDelegateApproval.sol";
8+
9+
contract Benchmark is Script {
10+
using stdJson for string;
11+
12+
IVault vault = IVault(0xAD7b4C162707E0B2b5f6fdDbD3f8538A5fbA0d60);
13+
IClearingHouse clearingHouse = IClearingHouse(0x82ac2CE43e33683c58BE4cDc40975E73aA50f459);
14+
15+
IDelegateApproval delegateApproval = IDelegateApproval(0xfd7bB5F6844a43c5469c972640Eddfa99597a547);
16+
address public immutable VETH = 0x8C835DFaA34e2AE61775e80EE29E2c724c6AE2BB;
17+
address public immutable USDC = 0x7F5c764cBc14f9669B88837ca1490cCa17c31607;
18+
19+
function run() public {
20+
require(block.chainid == 10, "script can only be run on optimism");
21+
string memory file = "broadcast/Deploy.s.sol/10/run-latest.json";
22+
string memory json = vm.readFile(file);
23+
24+
address depositRtr = json.readAddress(".transactions[1].additionalContracts[0].address");
25+
26+
address positionRtr = json.readAddress(".transactions[2].additionalContracts[0].address");
27+
28+
// ===========================
29+
// ======== Execution ========
30+
// ===========================
31+
32+
vm.startBroadcast();
33+
// Default ETH deposit in perpetual vault
34+
vault.depositEther{value: 0.00002 ether}();
35+
36+
// Optimized ETH deposit in perpetual vault
37+
(bool ok,) = payable(depositRtr).call{value: 0.00002 ether}("");
38+
require(ok, "Optimized ETH deposit");
39+
40+
// Default ERC20 deposit in perpetual vault
41+
ERC20(USDC).approve(address(vault), 250_000);
42+
vault.deposit(USDC, 250_000);
43+
44+
// Optimized ERC20 deposit in perpetual vault
45+
ERC20(USDC).approve(depositRtr, 250_000);
46+
(bool okDepositUSDC,) = payable(depositRtr).call(abi.encode(250_000));
47+
require(okDepositUSDC, "Optimized ETH deposit");
48+
49+
uint256 amount = 0.000000025 ether;
50+
delegateApproval.approve(positionRtr, 1);
51+
52+
// Default open exact output short VETH position
53+
clearingHouse.openPosition(
54+
IClearingHouse.OpenPositionParams({
55+
baseToken: VETH,
56+
isBaseToQuote: true,
57+
isExactInput: false,
58+
amount: amount,
59+
oppositeAmountBound: 0,
60+
deadline: type(uint256).max,
61+
sqrtPriceLimitX96: 0,
62+
referralCode: 0
63+
})
64+
);
65+
66+
// Default close VETH positions
67+
clearingHouse.closePosition(
68+
IClearingHouse.ClosePositionParams({
69+
baseToken: VETH,
70+
oppositeAmountBound: 0,
71+
deadline: type(uint256).max,
72+
sqrtPriceLimitX96: 0,
73+
referralCode: 0
74+
})
75+
);
76+
77+
// Optimized open exact output short VETH position
78+
(bool okPosition,) = payable(positionRtr).call(abi.encode(1, amount, 0, 0));
79+
require(okPosition, "Optimized VETH close position");
80+
81+
// Optimized close VETH positions
82+
(bool okClose,) = payable(positionRtr).call(abi.encode(5, 0, 0, 0));
83+
require(okClose, "Optimized VETH close position");
84+
85+
vm.stopBroadcast();
86+
}
87+
}

script/Deploy.s.sol

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,30 @@
22

33
pragma solidity ^0.8.16;
44

5-
import "forge-std/Script.sol";
6-
import {Counter} from "src/Counter.sol";
5+
import {Script} from "forge-std/Script.sol";
6+
import {IVault} from "src/interface/IVault.sol";
7+
import {IClearingHouse} from "src/interface/IClearingHouse.sol";
8+
import {IAccountBalance} from "src/interface/IAccountBalance.sol";
9+
import {PerpetualRouterFactory} from "src/PerpetualRouterFactory.sol";
710

811
contract Deploy is Script {
9-
Counter counter;
12+
IClearingHouse clearingHouse = IClearingHouse(0x82ac2CE43e33683c58BE4cDc40975E73aA50f459);
13+
IVault vault = IVault(0xAD7b4C162707E0B2b5f6fdDbD3f8538A5fbA0d60);
14+
IAccountBalance accountBalance = IAccountBalance(0xA7f3FC32043757039d5e13d790EE43edBcBa8b7c);
15+
16+
address public immutable USDC = 0x7F5c764cBc14f9669B88837ca1490cCa17c31607;
17+
address public immutable VETH = 0x8C835DFaA34e2AE61775e80EE29E2c724c6AE2BB;
1018

1119
function run() public {
12-
// Commented out for now until https://github.com/crytic/slither/pull/1461 is released.
13-
// vm.startBroadcast();
14-
counter = new Counter();
20+
require(block.chainid == 10, "script can only be run on optimism");
21+
vm.broadcast();
22+
PerpetualRouterFactory factory =
23+
new PerpetualRouterFactory(clearingHouse, accountBalance, vault);
24+
25+
vm.broadcast();
26+
factory.deploy(PerpetualRouterFactory.RouterTypes.DepositRouterType, USDC);
27+
28+
vm.broadcast();
29+
factory.deploy(PerpetualRouterFactory.RouterTypes.PositionRouterType, VETH);
1530
}
1631
}

src/Counter.sol

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/DepositRouter.sol

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.0;
3+
4+
import {ERC20} from "solmate/tokens/ERC20.sol";
5+
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
6+
7+
import {IVault} from "src/interface/IVault.sol";
8+
9+
/// @notice A router for depositing funds into the perpetual vault
10+
contract DepositRouter {
11+
/// @notice The token used for the router's deposits
12+
address public immutable TOKEN;
13+
14+
/// @notice The contract for the perpetual vault to accept deposits
15+
IVault public immutable PERPETUAL_VAULT;
16+
17+
constructor(address token, IVault vault) {
18+
TOKEN = token;
19+
PERPETUAL_VAULT = vault;
20+
}
21+
22+
function _deposit(uint256 amount) private {
23+
SafeTransferLib.safeTransferFrom(ERC20(TOKEN), msg.sender, address(this), amount);
24+
ERC20(TOKEN).approve(address(PERPETUAL_VAULT), amount);
25+
PERPETUAL_VAULT.depositFor(msg.sender, TOKEN, amount);
26+
}
27+
28+
// TODO: integer optimization after talking to the protocol
29+
fallback() external payable {
30+
uint256 amount = abi.decode(msg.data, (uint256));
31+
_deposit(amount);
32+
}
33+
34+
receive() external payable {
35+
PERPETUAL_VAULT.depositEtherFor{value: msg.value}(msg.sender);
36+
}
37+
}

0 commit comments

Comments
 (0)