Skip to content

Commit

Permalink
Inital perpetual open router (#1)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
alexkeating and mds1 authored May 1, 2023
1 parent b66daf2 commit 16d48eb
Show file tree
Hide file tree
Showing 27 changed files with 4,144 additions and 67 deletions.
23 changes: 2 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:

env:
FOUNDRY_PROFILE: ci
OPTIMISM_RPC_URL: ${{ secrets.OPTIMISM_RPC_URL }}

jobs:
build:
Expand Down Expand Up @@ -75,7 +76,7 @@ jobs:
uses: zgosalvez/github-actions-report-lcov@v2
with:
coverage-files: ./lcov.info
minimum-coverage: 100 # Set coverage threshold.
minimum-coverage: 80 # Set coverage threshold.

lint:
runs-on: ubuntu-latest
Expand All @@ -100,23 +101,3 @@ jobs:
run: |
scopelint --version
scopelint check
slither-analyze:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v3

- name: Run Slither
uses: crytic/[email protected]
id: slither # Required to reference this step in the next step.
with:
fail-on: none # Required to avoid failing the CI run regardless of findings.
sarif: results.sarif
slither-args: --filter-paths "./lib|./test" --exclude naming-convention

- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: ${{ steps.slither.outputs.sarif }}
9 changes: 9 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/solmate"]
path = lib/solmate
url = https://github.com/transmissions11/solmate
[submodule "lib/perp-curie-contract"]
path = lib/perp-curie-contract
url = https://github.com/perpetual-protocol/perp-curie-contract
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com//OpenZeppelin/openzeppelin-contracts
1,060 changes: 1,060 additions & 0 deletions broadcast/Benchmark.s.sol/10/run-1681856767.json

Large diffs are not rendered by default.

1,060 changes: 1,060 additions & 0 deletions broadcast/Benchmark.s.sol/10/run-latest.json

Large diffs are not rendered by default.

163 changes: 163 additions & 0 deletions broadcast/Deploy.s.sol/10/run-1681853983.json

Large diffs are not rendered by default.

163 changes: 163 additions & 0 deletions broadcast/Deploy.s.sol/10/run-latest.json

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[profile.default]
fs_permissions = [{ access = "read", path = "./broadcast" }]
optimizer = true
optimizer_runs = 10_000_000
solc_version = "0.8.16"
Expand All @@ -16,6 +17,13 @@

[fmt]
bracket_spacing = false
ignore = [
"src/interface/IAccountBalance.sol",
"src/lib/AccountMarket.sol",
"src/interface/IClearingHouse.sol",
"src/interface/IVault.sol",
"src/test/interface/IDelegateApproval.sol",
]
int_types = "long"
line_length = 100
multiline_func_header = "attributes_first"
Expand All @@ -24,3 +32,9 @@
single_line_statement_blocks = "single"
tab_width = 2
wrap_comments = true

# ===============================
# ======== RPC Endpoints ========
# ===============================
[rpc_endpoints]
optimism = "${OPTIMISM_RPC_URL}"
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at d00ace
1 change: 1 addition & 0 deletions lib/perp-curie-contract
Submodule perp-curie-contract added at 4e187e
1 change: 1 addition & 0 deletions lib/solmate
Submodule solmate added at 2001af
87 changes: 87 additions & 0 deletions script/Benchmark.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {Script, stdJson} from "forge-std/Script.sol";
import {DepositRouter} from "src/DepositRouter.sol";
import {PerpetualRouterFactory} from "src/PerpetualRouterFactory.sol";
import {ERC20} from "solmate/tokens/ERC20.sol";
import {IVault} from "src/interface/IVault.sol";
import {IClearingHouse} from "src/interface/IClearingHouse.sol";
import {IDelegateApproval} from "test/interface/IDelegateApproval.sol";

contract Benchmark is Script {
using stdJson for string;

IVault vault = IVault(0xAD7b4C162707E0B2b5f6fdDbD3f8538A5fbA0d60);
IClearingHouse clearingHouse = IClearingHouse(0x82ac2CE43e33683c58BE4cDc40975E73aA50f459);

IDelegateApproval delegateApproval = IDelegateApproval(0xfd7bB5F6844a43c5469c972640Eddfa99597a547);
address public immutable VETH = 0x8C835DFaA34e2AE61775e80EE29E2c724c6AE2BB;
address public immutable USDC = 0x7F5c764cBc14f9669B88837ca1490cCa17c31607;

function run() public {
require(block.chainid == 10, "script can only be run on optimism");
string memory file = "broadcast/Deploy.s.sol/10/run-latest.json";
string memory json = vm.readFile(file);

address depositRtr = json.readAddress(".transactions[1].additionalContracts[0].address");

address positionRtr = json.readAddress(".transactions[2].additionalContracts[0].address");

// ===========================
// ======== Execution ========
// ===========================

vm.startBroadcast();
// Default ETH deposit in perpetual vault
vault.depositEther{value: 0.00002 ether}();

// Optimized ETH deposit in perpetual vault
(bool ok,) = payable(depositRtr).call{value: 0.00002 ether}("");
require(ok, "Optimized ETH deposit");

// Default ERC20 deposit in perpetual vault
ERC20(USDC).approve(address(vault), 250_000);
vault.deposit(USDC, 250_000);

// Optimized ERC20 deposit in perpetual vault
ERC20(USDC).approve(depositRtr, 250_000);
(bool okDepositUSDC,) = payable(depositRtr).call(abi.encode(250_000));
require(okDepositUSDC, "Optimized ETH deposit");

uint256 amount = 0.000000025 ether;
delegateApproval.approve(positionRtr, 1);

// Default open exact output short VETH position
clearingHouse.openPosition(
IClearingHouse.OpenPositionParams({
baseToken: VETH,
isBaseToQuote: true,
isExactInput: false,
amount: amount,
oppositeAmountBound: 0,
deadline: type(uint256).max,
sqrtPriceLimitX96: 0,
referralCode: 0
})
);

// Default close VETH positions
clearingHouse.closePosition(
IClearingHouse.ClosePositionParams({
baseToken: VETH,
oppositeAmountBound: 0,
deadline: type(uint256).max,
sqrtPriceLimitX96: 0,
referralCode: 0
})
);

// Optimized open exact output short VETH position
(bool okPosition,) = payable(positionRtr).call(abi.encode(1, amount, 0, 0));
require(okPosition, "Optimized VETH close position");

// Optimized close VETH positions
(bool okClose,) = payable(positionRtr).call(abi.encode(5, 0, 0, 0));
require(okClose, "Optimized VETH close position");

vm.stopBroadcast();
}
}
27 changes: 21 additions & 6 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,30 @@

pragma solidity ^0.8.16;

import "forge-std/Script.sol";
import {Counter} from "src/Counter.sol";
import {Script} from "forge-std/Script.sol";
import {IVault} from "src/interface/IVault.sol";
import {IClearingHouse} from "src/interface/IClearingHouse.sol";
import {IAccountBalance} from "src/interface/IAccountBalance.sol";
import {PerpetualRouterFactory} from "src/PerpetualRouterFactory.sol";

contract Deploy is Script {
Counter counter;
IClearingHouse clearingHouse = IClearingHouse(0x82ac2CE43e33683c58BE4cDc40975E73aA50f459);
IVault vault = IVault(0xAD7b4C162707E0B2b5f6fdDbD3f8538A5fbA0d60);
IAccountBalance accountBalance = IAccountBalance(0xA7f3FC32043757039d5e13d790EE43edBcBa8b7c);

address public immutable USDC = 0x7F5c764cBc14f9669B88837ca1490cCa17c31607;
address public immutable VETH = 0x8C835DFaA34e2AE61775e80EE29E2c724c6AE2BB;

function run() public {
// Commented out for now until https://github.com/crytic/slither/pull/1461 is released.
// vm.startBroadcast();
counter = new Counter();
require(block.chainid == 10, "script can only be run on optimism");
vm.broadcast();
PerpetualRouterFactory factory =
new PerpetualRouterFactory(clearingHouse, accountBalance, vault);

vm.broadcast();
factory.deploy(PerpetualRouterFactory.RouterTypes.DepositRouterType, USDC);

vm.broadcast();
factory.deploy(PerpetualRouterFactory.RouterTypes.PositionRouterType, VETH);
}
}
14 changes: 0 additions & 14 deletions src/Counter.sol

This file was deleted.

37 changes: 37 additions & 0 deletions src/DepositRouter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import {ERC20} from "solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";

import {IVault} from "src/interface/IVault.sol";

/// @notice A router for depositing funds into the perpetual vault
contract DepositRouter {
/// @notice The token used for the router's deposits
address public immutable TOKEN;

/// @notice The contract for the perpetual vault to accept deposits
IVault public immutable PERPETUAL_VAULT;

constructor(address token, IVault vault) {
TOKEN = token;
PERPETUAL_VAULT = vault;
}

function _deposit(uint256 amount) private {
SafeTransferLib.safeTransferFrom(ERC20(TOKEN), msg.sender, address(this), amount);
ERC20(TOKEN).approve(address(PERPETUAL_VAULT), amount);
PERPETUAL_VAULT.depositFor(msg.sender, TOKEN, amount);
}

// TODO: integer optimization after talking to the protocol
fallback() external payable {
uint256 amount = abi.decode(msg.data, (uint256));
_deposit(amount);
}

receive() external payable {
PERPETUAL_VAULT.depositEtherFor{value: msg.value}(msg.sender);
}
}
Loading

0 comments on commit 16d48eb

Please sign in to comment.