-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 958808f
Showing
9 changed files
with
391 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
pull_request: | ||
workflow_dispatch: | ||
|
||
env: | ||
FOUNDRY_PROFILE: ci | ||
|
||
jobs: | ||
check: | ||
strategy: | ||
fail-fast: true | ||
|
||
name: Foundry project | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
submodules: recursive | ||
|
||
- name: Install Foundry | ||
uses: foundry-rs/foundry-toolchain@v1 | ||
with: | ||
version: nightly | ||
|
||
- name: Show Forge version | ||
run: | | ||
forge --version | ||
- name: Run Forge fmt | ||
run: | | ||
forge fmt --check | ||
id: fmt | ||
|
||
- name: Run Forge build | ||
run: | | ||
forge build --sizes | ||
id: build | ||
|
||
- name: Run Forge tests | ||
run: | | ||
forge test -vvv | ||
id: test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Compiler files | ||
cache/ | ||
out/ | ||
|
||
# Ignores development broadcast logs | ||
!/broadcast | ||
/broadcast/*/31337/ | ||
/broadcast/**/dry-run/ | ||
|
||
# Docs | ||
docs/ | ||
|
||
# Dotenv file | ||
.env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "lib/v4-periphery"] | ||
path = lib/v4-periphery | ||
url = https://github.com/uniswap/v4-periphery |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
## Foundry | ||
|
||
**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** | ||
|
||
Foundry consists of: | ||
|
||
- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). | ||
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. | ||
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. | ||
- **Chisel**: Fast, utilitarian, and verbose solidity REPL. | ||
|
||
## Documentation | ||
|
||
https://book.getfoundry.sh/ | ||
|
||
## Usage | ||
|
||
### Build | ||
|
||
```shell | ||
$ forge build | ||
``` | ||
|
||
### Test | ||
|
||
```shell | ||
$ forge test | ||
``` | ||
|
||
### Format | ||
|
||
```shell | ||
$ forge fmt | ||
``` | ||
|
||
### Gas Snapshots | ||
|
||
```shell | ||
$ forge snapshot | ||
``` | ||
|
||
### Anvil | ||
|
||
```shell | ||
$ anvil | ||
``` | ||
|
||
### Deploy | ||
|
||
```shell | ||
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key> | ||
``` | ||
|
||
### Cast | ||
|
||
```shell | ||
$ cast <subcommand> | ||
``` | ||
|
||
### Help | ||
|
||
```shell | ||
$ forge --help | ||
$ anvil --help | ||
$ cast --help | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/blob/master/crates/config/README.md#all-options |
Submodule v4-periphery
added at
5d5dbf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
@ensdomains/=lib/v4-periphery/lib/v4-core/node_modules/@ensdomains/ | ||
@openzeppelin/=lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/ | ||
@openzeppelin/contracts/=lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/contracts/ | ||
@uniswap/v4-core/=lib/v4-periphery/lib/v4-core/ | ||
ds-test/=lib/v4-periphery/lib/v4-core/lib/forge-std/lib/ds-test/src/ | ||
erc4626-tests/=lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/lib/erc4626-tests/ | ||
forge-gas-snapshot/=lib/v4-periphery/lib/permit2/lib/forge-gas-snapshot/src/ | ||
forge-std/=lib/v4-periphery/lib/v4-core/lib/forge-std/src/ | ||
hardhat/=lib/v4-periphery/lib/v4-core/node_modules/hardhat/ | ||
openzeppelin-contracts/=lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/ | ||
permit2/=lib/v4-periphery/lib/permit2/ | ||
solmate/=lib/v4-periphery/lib/v4-core/lib/solmate/ | ||
v4-core/=lib/v4-periphery/lib/v4-core/src/ | ||
v4-periphery/=lib/v4-periphery/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.0; | ||
|
||
import {BaseHook} from "v4-periphery/src/base/hooks/BaseHook.sol"; | ||
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; | ||
import {Hooks} from "v4-core/libraries/Hooks.sol"; | ||
|
||
import {StateLibrary} from "v4-core/libraries/StateLibrary.sol"; | ||
import {TickMath} from "v4-core/libraries/TickMath.sol"; | ||
|
||
import {PoolId} from "v4-core/types/PoolId.sol"; | ||
import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol"; | ||
|
||
import {PoolKey} from "v4-core/types/PoolKey.sol"; | ||
|
||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
|
||
import {BalanceDelta} from "v4-core/types/BalanceDelta.sol"; | ||
|
||
import {CurrencyLibrary, Currency} from "v4-core/types/Currency.sol"; | ||
|
||
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; | ||
import {BeforeSwapDelta, BeforeSwapDeltaLibrary} from "v4-core/types/BeforeSwapDelta.sol"; | ||
import {LPFeeLibrary} from "v4-core/libraries/LPFeeLibrary.sol"; | ||
|
||
contract GasPriceHook is BaseHook { | ||
using LPFeeLibrary for uint24; | ||
|
||
// keep track of the moving average gas price | ||
uint128 movingAverageGasPrice; | ||
|
||
// num of times the moving average is updated | ||
// need this as the denominator to update it next time based on moving average formulae | ||
uint104 public movingAverageGasPriceCount; | ||
|
||
// default base fee that we'll charging | ||
uint24 public constant BASE_FEE = 5000; // 0.5% | ||
|
||
error MustUseDynamicFee(); | ||
|
||
constructor(IPoolManager _poolManager) BaseHook(_poolManager) { | ||
updateMovingAverage(); | ||
} | ||
|
||
function getHookPermissions() | ||
public | ||
pure | ||
override | ||
returns (Hooks.Permissions memory) | ||
{ | ||
return | ||
Hooks.Permissions({ | ||
beforeInitialize: true, | ||
afterInitialize: false, | ||
beforeAddLiquidity: false, | ||
afterAddLiquidity: false, | ||
beforeRemoveLiquidity: false, | ||
afterRemoveLiquidity: false, | ||
beforeSwap: true, | ||
afterSwap: true, | ||
beforeDonate: false, | ||
afterDonate: false, | ||
beforeSwapReturnDelta: false, | ||
afterSwapReturnDelta: false, | ||
afterAddLiquidityReturnDelta: false, | ||
afterRemoveLiquidityReturnDelta: false | ||
}); | ||
} | ||
|
||
function beforeInitialize( | ||
address, | ||
PoolKey calldata key, | ||
uint160 | ||
) external pure override returns (bytes4) { | ||
// `.isDynamicFee()` function comes from using | ||
// the `SwapFeeLibrary` for `uint24` | ||
if (!key.fee.isDynamicFee()) revert MustUseDynamicFee(); | ||
return this.beforeInitialize.selector; | ||
} | ||
|
||
function afterSwap( | ||
address, | ||
PoolKey calldata, | ||
IPoolManager.SwapParams calldata, | ||
BalanceDelta, | ||
bytes calldata | ||
) external override returns (bytes4, int128) { | ||
updateMovingAverage(); | ||
return (this.afterSwap.selector, 0); | ||
} | ||
|
||
function beforeSwap( | ||
address, | ||
PoolKey calldata, | ||
IPoolManager.SwapParams calldata, | ||
bytes calldata | ||
) | ||
external | ||
view | ||
override | ||
onlyPoolManager | ||
returns (bytes4, BeforeSwapDelta, uint24) | ||
{ | ||
uint24 fee = getFee(); | ||
|
||
uint24 feeWithFlag = fee | LPFeeLibrary.OVERRIDE_FEE_FLAG; | ||
|
||
return ( | ||
this.beforeSwap.selector, | ||
BeforeSwapDeltaLibrary.ZERO_DELTA, | ||
feeWithFlag | ||
); | ||
} | ||
|
||
function getFee() internal view returns (uint24) { | ||
uint128 gasPrice = uint128(tx.gasprice); | ||
|
||
// if gasPrice > movingAverageGasPrice * 1.1 , the half the fees | ||
if (gasPrice > (movingAverageGasPrice * 11) / 10) { | ||
return BASE_FEE / 2; | ||
} | ||
|
||
// if gasPrice < movingAverageGasPrice * 0.9 , then double the fees | ||
if (gasPrice < (movingAverageGasPrice * 9) / 10) { | ||
return BASE_FEE * 2; | ||
} | ||
|
||
return BASE_FEE; | ||
} | ||
|
||
// updates moving average gas price | ||
function updateMovingAverage() internal { | ||
uint128 gasPrice = uint128(tx.gasprice); | ||
|
||
// new average = ((old average * # of transactions Tracked) + Current gas price) / (# of transactions tracked + 1) | ||
movingAverageGasPrice = | ||
((movingAverageGasPrice * movingAverageGasPriceCount) + gasPrice) / | ||
(movingAverageGasPriceCount + 1); | ||
movingAverageGasPriceCount++; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.0; | ||
|
||
import {Test} from "forge-std/Test.sol"; | ||
|
||
import {BaseHook} from "v4-periphery/src/base/hooks/BaseHook.sol"; | ||
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; | ||
import {Hooks} from "v4-core/libraries/Hooks.sol"; | ||
import {LPFeeLibrary} from "v4-core/libraries/LPFeeLibrary.sol"; | ||
import {StateLibrary} from "v4-core/libraries/StateLibrary.sol"; | ||
import {TickMath} from "v4-core/libraries/TickMath.sol"; | ||
|
||
import {PoolId} from "v4-core/types/PoolId.sol"; | ||
import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol"; | ||
|
||
import {PoolKey} from "v4-core/types/PoolKey.sol"; | ||
|
||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
|
||
import {BalanceDelta} from "v4-core/types/BalanceDelta.sol"; | ||
|
||
import {Currency} from "v4-core/types/Currency.sol"; | ||
|
||
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; | ||
|
||
// uniswap-v4 test utils | ||
import {Deployers} from "@uniswap/v4-core/test/utils/Deployers.sol"; | ||
import {PoolSwapTest} from "v4-core/test/PoolSwapTest.sol"; | ||
import {MockERC20} from "solmate/src/test/utils/mocks/MockERC20.sol"; | ||
|
||
import {GasPriceHook} from "src/GasPriceHook.sol"; | ||
|
||
contract GasPriceHooktest is Test, Deployers { | ||
using StateLibrary for IPoolManager; | ||
using FixedPointMathLib for uint256; | ||
|
||
GasPriceHook hook; | ||
|
||
function setUp() public { | ||
// Deploy v4 core contracts | ||
deployFreshManagerAndRouters(); | ||
|
||
// Deploy two test tokens | ||
|
||
deployMintAndApprove2Currencies(); | ||
|
||
// deploy the hook | ||
uint160 flags = uint160( | ||
Hooks.BEFORE_INITIALIZE_FLAG | | ||
Hooks.BEFORE_SWAP_FLAG | | ||
Hooks.AFTER_SWAP_FLAG | ||
); | ||
address hookAddress = address(flags); | ||
|
||
// set gas price = 10 gwei and then deploy | ||
vm.txGasPrice(10 gwei); | ||
|
||
deployCodeTo("GasPriceHook", abi.encode(manager, ""), hookAddress); | ||
|
||
// initialize hook | ||
hook = GasPriceHook(hookAddress); | ||
|
||
// initialize a pool | ||
(key, ) = initPool( | ||
currency0, | ||
currency1, | ||
hook, | ||
LPFeeLibrary.DYNAMIC_FEE_FLAG, | ||
SQRT_PRICE_1_1 | ||
); | ||
|
||
// adding liquidity | ||
modifyLiquidityRouter.modifyLiquidity( | ||
key, | ||
IPoolManager.ModifiyLiquidityParams({ | ||
tickLower: -60, | ||
tickUpper: 60, | ||
liquidityDelta: 100 ether, | ||
salt: bytes32(0) | ||
}), | ||
ZERO_BYTES | ||
); | ||
} | ||
|
||
function test_feeUpdatesWithGasPrice() public { | ||
// setup swap params | ||
|
||
// 1. swap with gasprice = 10 gwei | ||
|
||
// 2. swap with gas price = 4 gwei | ||
vm.txGasPrice(4 gwei); | ||
|
||
// 3. swap with gas price = 12 gwei | ||
vm.txGasPrice(12 gwei); | ||
|
||
// assert | ||
} | ||
|
||
|
||
} |