Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvinparikh committed Jan 3, 2025
0 parents commit 958808f
Show file tree
Hide file tree
Showing 9 changed files with 391 additions and 0 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/test.yml
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
14 changes: 14 additions & 0 deletions .gitignore
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
3 changes: 3 additions & 0 deletions .gitmodules
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
66 changes: 66 additions & 0 deletions README.md
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
```
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/blob/master/crates/config/README.md#all-options
1 change: 1 addition & 0 deletions lib/v4-periphery
Submodule v4-periphery added at 5d5dbf
14 changes: 14 additions & 0 deletions remappings.txt
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/
142 changes: 142 additions & 0 deletions src/GasPriceHook.sol
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++;
}
}
100 changes: 100 additions & 0 deletions test/GasPriceHook.t.sol
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
}


}

0 comments on commit 958808f

Please sign in to comment.