generated from PaulRBerg/foundry-template
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #32 from alcueca/new-wrappers
Solidly wrapper
- Loading branch information
Showing
6 changed files
with
468 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,70 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity >=0.8.19 <=0.9.0; | ||
|
||
import { Script } from "forge-std/Script.sol"; | ||
import { console2 } from "forge-std/console2.sol"; | ||
|
||
import "./Network.sol"; | ||
|
||
import { Registry } from "src/Registry.sol"; | ||
|
||
import { SolidlyWrapper } from "../src/solidly/SolidlyWrapper.sol"; | ||
|
||
/// @dev See the Solidity Scripting tutorial: https://book.getfoundry.sh/tutorials/solidity-scripting | ||
contract SolidlyDeploy is Script { | ||
bytes32 public constant SALT = keccak256("ultrasecr.eth"); | ||
|
||
struct Fork { | ||
string name; | ||
address factory; | ||
address weth; | ||
address usdc; | ||
} | ||
|
||
mapping(Network network => Fork fork) public forks; | ||
|
||
Registry internal registry = Registry(0xa348320114210b8F4eaF1b0795aa8F70803a93EA); | ||
|
||
constructor() { | ||
forks[BASE] = Fork({ | ||
name: "AerodromeWrapper", | ||
factory: 0x420DD381b31aEf6683db6B902084cB0FFECe40Da, | ||
weth: 0x4200000000000000000000000000000000000006, | ||
usdc: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 | ||
}); | ||
forks[OPTIMISM] = Fork({ | ||
name: "VelodromeWrapper", | ||
factory: 0xF1046053aa5682b4F9a81b5481394DA16BE5FF5a, | ||
weth: 0x4200000000000000000000000000000000000006, | ||
usdc: 0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85 | ||
}); | ||
} | ||
|
||
function run() public { | ||
console2.log("Deploying as %s", msg.sender); | ||
|
||
Network network = currentNetwork(); | ||
|
||
Fork memory fork = forks[network]; | ||
require(fork.weth != address(0), "Fork not supported"); | ||
|
||
bytes memory paramsBytes = abi.encode(fork.factory, fork.weth, fork.usdc); | ||
|
||
string memory key = fork.name; | ||
|
||
if (keccak256(registry.get(key)) != keccak256(paramsBytes)) { | ||
console2.log("Updating registry"); | ||
vm.broadcast(); | ||
registry.set(key, paramsBytes); | ||
} | ||
|
||
(address _factory, address _weth, address _usdc) = abi.decode(registry.get(key), (address, address, address)); | ||
console2.log("Factory: %s", _factory); | ||
console2.log("WETH: %s", _weth); | ||
console2.log("USDC: %s", _usdc); | ||
|
||
vm.broadcast(); | ||
SolidlyWrapper wrapper = new SolidlyWrapper{ salt: SALT }(key, registry); | ||
console2.log("SolidlyWrapper deployed at: %s", address(wrapper)); | ||
} | ||
} |
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,137 @@ | ||
// SPDX-License-Identifier: MIT | ||
// Thanks to sunnyRK, yashnaman & ultrasecr.eth | ||
pragma solidity ^0.8.19; | ||
|
||
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; | ||
|
||
import { Registry } from "src/Registry.sol"; | ||
|
||
import { IPoolFactory } from "./interfaces/IPoolFactory.sol"; | ||
import { IPoolCallee } from "./interfaces/IPoolCallee.sol"; | ||
import { IPool } from "./interfaces/IPool.sol"; | ||
|
||
import { BaseWrapper, IERC7399, IERC20 } from "../BaseWrapper.sol"; | ||
|
||
/// @dev Solidly Flash Lender that uses Solidly Pools as source of liquidity. | ||
/// Solidly allows pushing repayments, so we override `_repayTo`. | ||
contract SolidlyWrapper is BaseWrapper, IPoolCallee { | ||
using { canLoan, balance } for IPool; | ||
|
||
uint256 private constant WAD = 1e18; | ||
|
||
error Unauthorized(); | ||
error UnknownPool(); | ||
error UnsupportedCurrency(address asset); | ||
|
||
// CONSTANTS | ||
IPoolFactory public immutable factory; | ||
|
||
// DEFAULT ASSETS | ||
address public immutable weth; | ||
address public immutable usdc; | ||
|
||
/// @param reg Registry storing constructor parameters | ||
constructor(string memory name, Registry reg) { | ||
// @param factory_ Solidly SolidlyFactory address | ||
// @param weth_ Weth contract used in Solidly Pairs | ||
// @param usdc_ usdc contract used in Solidly Pairs | ||
(factory, weth, usdc) = abi.decode(reg.getSafe(name), (IPoolFactory, address, address)); | ||
} | ||
|
||
/** | ||
* @dev Get the Solidly Pool that will be used as the source of a loan. The opposite asset will be WETH, except for | ||
* WETH that will be usdc. | ||
* @param asset The loan currency. | ||
* @param amount The amount of assets to borrow. | ||
* @return pool The Solidly Pool that will be used as the source of the flash loan. | ||
*/ | ||
function cheapestPool(address asset, uint256 amount) public view returns (IPool pool, uint256 fee, bool stable) { | ||
address assetOther = asset == weth ? usdc : weth; | ||
IPool sPool = _pool(asset, assetOther, true); | ||
IPool vPool = _pool(asset, assetOther, false); | ||
|
||
uint256 sFee = address(sPool) != address(0) ? factory.getFee(sPool, true) : type(uint256).max; | ||
uint256 vFee = address(vPool) != address(0) ? factory.getFee(vPool, false) : type(uint256).max; | ||
|
||
if (sFee < vFee) { | ||
if (sPool.canLoan(asset, amount)) return (sPool, sFee, true); | ||
if (vPool.canLoan(asset, amount)) return (vPool, vFee, false); | ||
} else { | ||
if (vPool.canLoan(asset, amount)) return (vPool, vFee, false); | ||
if (sPool.canLoan(asset, amount)) return (sPool, sFee, true); | ||
} | ||
} | ||
|
||
/// @inheritdoc IERC7399 | ||
function maxFlashLoan(address asset) external view returns (uint256) { | ||
return _maxFlashLoan(asset); | ||
} | ||
|
||
function _feeAmount(uint256 amount, uint256 fee) internal pure returns (uint256) { | ||
uint256 feeWAD = fee * 1e14; | ||
uint256 derivedFee = Math.mulDiv(WAD, WAD, WAD - feeWAD, Math.Rounding.Ceil) - WAD; | ||
return Math.mulDiv(amount, derivedFee, WAD, Math.Rounding.Ceil); | ||
} | ||
|
||
/// @inheritdoc IERC7399 | ||
function flashFee(address asset, uint256 amount) external view returns (uint256) { | ||
(IPool pool, uint256 fee,) = cheapestPool(asset, amount); | ||
if (address(pool) == address(0)) revert UnsupportedCurrency(asset); | ||
|
||
return _feeAmount(amount, fee); | ||
} | ||
|
||
/// @inheritdoc IPoolCallee | ||
function hook(address sender, uint256 amount0, uint256 amount1, bytes calldata params) external override { | ||
(address asset0, address asset1, uint256 fee, bool stable, bytes memory data) = | ||
abi.decode(params, (address, address, uint256, bool, bytes)); | ||
|
||
IPool pool = _pool(asset0, asset1, stable); | ||
if (msg.sender != address(pool)) revert UnknownPool(); | ||
if (sender != address(this)) revert Unauthorized(); | ||
|
||
(address asset, uint256 amount) = amount0 > 0 ? (asset0, amount0) : (asset1, amount1); | ||
|
||
_bridgeToCallback(asset, amount, _feeAmount(amount, fee), data); | ||
} | ||
|
||
function _flashLoan(address asset, uint256 amount, bytes memory data) internal override { | ||
(IPool pool, uint256 fee, bool stable) = cheapestPool(asset, amount); | ||
if (address(pool) == address(0)) revert UnsupportedCurrency(asset); | ||
|
||
(address asset0, address asset1) = pool.tokens(); | ||
uint256 amount0 = asset == asset0 ? amount : 0; | ||
uint256 amount1 = asset == asset1 ? amount : 0; | ||
bytes memory params = abi.encode(asset0, asset1, fee, stable, data); | ||
|
||
pool.swap(amount0, amount1, address(this), params); | ||
} | ||
|
||
function _repayTo() internal view override returns (address) { | ||
return msg.sender; | ||
} | ||
|
||
function _pool(address tokenA, address tokenB, bool stable) internal view returns (IPool pool) { | ||
(tokenA, tokenB) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); | ||
pool = factory.getPool(tokenA, tokenB, stable); | ||
} | ||
|
||
function _maxFlashLoan(address asset) internal view returns (uint256 max) { | ||
address assetOther = asset == weth ? usdc : weth; | ||
IPool stable = _pool(asset, assetOther, true); | ||
IPool volatile = _pool(asset, assetOther, false); | ||
|
||
uint256 stableBalance = balance(stable, asset); | ||
uint256 volatileBalance = balance(volatile, asset); | ||
|
||
return stableBalance > volatileBalance ? stableBalance : volatileBalance; | ||
} | ||
} | ||
|
||
function canLoan(IPool pool, address asset, uint256 amount) view returns (bool) { | ||
return balance(pool, asset) >= amount; | ||
} | ||
|
||
function balance(IPool pool, address asset) view returns (uint256) { | ||
return IERC20(asset).balanceOf(address(pool)); | ||
} |
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,115 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.4; | ||
|
||
interface IPool { | ||
struct Observation { | ||
uint256 timestamp; | ||
uint256 reserve0Cumulative; | ||
uint256 reserve1Cumulative; | ||
} | ||
|
||
error BelowMinimumK(); | ||
error DepositsNotEqual(); | ||
error FactoryAlreadySet(); | ||
error InsufficientInputAmount(); | ||
error InsufficientLiquidity(); | ||
error InsufficientLiquidityBurned(); | ||
error InsufficientLiquidityMinted(); | ||
error InsufficientOutputAmount(); | ||
error InvalidTo(); | ||
error IsPaused(); | ||
error K(); | ||
error NotEmergencyCouncil(); | ||
error StringTooLong(string str); | ||
|
||
function DOMAIN_SEPARATOR() external view returns (bytes32); | ||
function allowance(address owner, address spender) external view returns (uint256); | ||
function approve(address spender, uint256 amount) external returns (bool); | ||
function balanceOf(address account) external view returns (uint256); | ||
function blockTimestampLast() external view returns (uint256); | ||
function burn(address to) external returns (uint256 amount0, uint256 amount1); | ||
function claimFees() external returns (uint256 claimed0, uint256 claimed1); | ||
function claimable0(address) external view returns (uint256); | ||
function claimable1(address) external view returns (uint256); | ||
function currentCumulativePrices() | ||
external | ||
view | ||
returns (uint256 reserve0Cumulative, uint256 reserve1Cumulative, uint256 blockTimestamp); | ||
function decimals() external view returns (uint8); | ||
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); | ||
function eip712Domain() | ||
external | ||
view | ||
returns ( | ||
bytes1 fields, | ||
string memory name, | ||
string memory version, | ||
uint256 chainId, | ||
address verifyingContract, | ||
bytes32 salt, | ||
uint256[] memory extensions | ||
); | ||
function factory() external view returns (address); | ||
function getAmountOut(uint256 amountIn, address tokenIn) external view returns (uint256); | ||
function getK() external returns (uint256); | ||
function getReserves() external view returns (uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast); | ||
function increaseAllowance(address spender, uint256 addedValue) external returns (bool); | ||
function index0() external view returns (uint256); | ||
function index1() external view returns (uint256); | ||
function initialize(address _token0, address _token1, bool _stable) external; | ||
function lastObservation() external view returns (Observation memory); | ||
function metadata() | ||
external | ||
view | ||
returns (uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, bool st, address t0, address t1); | ||
function mint(address to) external returns (uint256 liquidity); | ||
function name() external view returns (string memory); | ||
function nonces(address owner) external view returns (uint256); | ||
function observationLength() external view returns (uint256); | ||
function observations(uint256) | ||
external | ||
view | ||
returns (uint256 timestamp, uint256 reserve0Cumulative, uint256 reserve1Cumulative); | ||
function periodSize() external view returns (uint256); | ||
function permit( | ||
address owner, | ||
address spender, | ||
uint256 value, | ||
uint256 deadline, | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s | ||
) | ||
external; | ||
function poolFees() external view returns (address); | ||
function prices(address tokenIn, uint256 amountIn, uint256 points) external view returns (uint256[] memory); | ||
function quote(address tokenIn, uint256 amountIn, uint256 granularity) external view returns (uint256 amountOut); | ||
function reserve0() external view returns (uint256); | ||
function reserve0CumulativeLast() external view returns (uint256); | ||
function reserve1() external view returns (uint256); | ||
function reserve1CumulativeLast() external view returns (uint256); | ||
function sample( | ||
address tokenIn, | ||
uint256 amountIn, | ||
uint256 points, | ||
uint256 window | ||
) | ||
external | ||
view | ||
returns (uint256[] memory); | ||
function setName(string memory __name) external; | ||
function setSymbol(string memory __symbol) external; | ||
function skim(address to) external; | ||
function stable() external view returns (bool); | ||
function supplyIndex0(address) external view returns (uint256); | ||
function supplyIndex1(address) external view returns (uint256); | ||
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes memory data) external; | ||
function symbol() external view returns (string memory); | ||
function sync() external; | ||
function token0() external view returns (address); | ||
function token1() external view returns (address); | ||
function tokens() external view returns (address, address); | ||
function totalSupply() external view returns (uint256); | ||
function transfer(address to, uint256 amount) external returns (bool); | ||
function transferFrom(address from, address to, uint256 amount) external returns (bool); | ||
} |
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 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
interface IPoolCallee { | ||
function hook(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external; | ||
} |
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,35 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.4; | ||
|
||
import { IPool } from "./IPool.sol"; | ||
|
||
interface IPoolFactory { | ||
error FeeInvalid(); | ||
error FeeTooHigh(); | ||
error InvalidPool(); | ||
error NotFeeManager(); | ||
error NotPauser(); | ||
error NotVoter(); | ||
error PoolAlreadyExists(); | ||
error SameAddress(); | ||
error ZeroAddress(); | ||
error ZeroFee(); | ||
|
||
function MAX_FEE() external view returns (uint256); | ||
function ZERO_FEE_INDICATOR() external view returns (uint256); | ||
function allPools(uint256) external view returns (address); | ||
function allPoolsLength() external view returns (uint256); | ||
function createPool(address tokenA, address tokenB, bool stable) external returns (address pool); | ||
function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool); | ||
function customFee(address) external view returns (uint256); | ||
function feeManager() external view returns (address); | ||
function getFee(IPool pool, bool _stable) external view returns (uint256); | ||
function getPool(address tokenA, address tokenB, uint24 fee) external view returns (IPool); | ||
function getPool(address tokenA, address tokenB, bool stable) external view returns (IPool); | ||
function implementation() external view returns (address); | ||
function isPaused() external view returns (bool); | ||
function isPool(IPool pool) external view returns (bool); | ||
function stableFee() external view returns (uint256); | ||
function volatileFee() external view returns (uint256); | ||
function voter() external view returns (address); | ||
} |
Oops, something went wrong.