-
Notifications
You must be signed in to change notification settings - Fork 47
Yield Staking Zap #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 0x
Are you sure you want to change the base?
Changes from 9 commits
93be32b
6ace6d6
f31ec58
79a837b
92069ad
02d7752
b231305
f5cfa48
456c6d8
109d649
edd0dcf
cbc1ecf
a940d49
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,336 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
// SPDX-License-Identifier: MIT | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
pragma solidity ^0.8.0; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
import "./interface/INFTXInventoryStaking.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||
import "./interface/INFTXLPStaking.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||
import "./interface/INFTXVaultFactory.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||
import "./interface/IUniswapV2Router01.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||
import "./util/Ownable.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||
import "./util/ReentrancyGuard.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||
import "./util/SafeERC20Upgradeable.sol"; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* @notice A partial WETH interface. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
interface IWETH { | ||||||||||||||||||||||||||||||||||||||||||||||
function deposit() external payable; | ||||||||||||||||||||||||||||||||||||||||||||||
function transfer(address to, uint value) external returns (bool); | ||||||||||||||||||||||||||||||||||||||||||||||
function withdraw(uint) external; | ||||||||||||||||||||||||||||||||||||||||||||||
function balanceOf(address to) external view returns (uint256); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* @notice Allows users to buy and stake tokens into either an inventory or liquidity | ||||||||||||||||||||||||||||||||||||||||||||||
* pool, handling the steps between buying and staking across 0x and sushi. | ||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||
* @author Twade | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
contract NFTXYieldStakingZap is Ownable, ReentrancyGuard { | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
using SafeERC20Upgradeable for IERC20Upgradeable; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/// @notice Allows zap to be paused | ||||||||||||||||||||||||||||||||||||||||||||||
bool public paused = false; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/// @notice Sets our 0x swap target | ||||||||||||||||||||||||||||||||||||||||||||||
address payable private swapTarget; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/// @notice Holds the mapping of our sushi router | ||||||||||||||||||||||||||||||||||||||||||||||
IUniswapV2Router01 public immutable sushiRouter; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/// @notice An interface for the WETH contract | ||||||||||||||||||||||||||||||||||||||||||||||
IWETH public immutable WETH; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/// @notice An interface for the NFTX Vault Factory contract | ||||||||||||||||||||||||||||||||||||||||||||||
INFTXInventoryStaking public immutable inventoryStaking; | ||||||||||||||||||||||||||||||||||||||||||||||
INFTXLPStaking public immutable lpStaking; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/// @notice An interface for the NFTX Vault Factory contract | ||||||||||||||||||||||||||||||||||||||||||||||
INFTXVaultFactory public immutable nftxFactory; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/// @notice A mapping of NFTX Vault IDs to their address corresponding | ||||||||||||||||||||||||||||||||||||||||||||||
/// vault contract address | ||||||||||||||||||||||||||||||||||||||||||||||
mapping(uint256 => address) public nftxVaultAddresses; | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this being saved, the factory stores this already no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This just creates gas savings by allowing us by bypassing subsequent calls to the factory contract and instead just looking up the internal ID -> address mapping. Isn't an astronomical saving, but does add up. |
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* @notice Initialises our zap and sets our internal addresses that will be referenced | ||||||||||||||||||||||||||||||||||||||||||||||
* in our contract. This allows for varied addresses based on the network. | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
constructor( | ||||||||||||||||||||||||||||||||||||||||||||||
address _nftxFactory, | ||||||||||||||||||||||||||||||||||||||||||||||
address _inventoryStaking, | ||||||||||||||||||||||||||||||||||||||||||||||
address _lpStaking, | ||||||||||||||||||||||||||||||||||||||||||||||
address _sushiRouter, | ||||||||||||||||||||||||||||||||||||||||||||||
address _weth | ||||||||||||||||||||||||||||||||||||||||||||||
) Ownable() ReentrancyGuard() { | ||||||||||||||||||||||||||||||||||||||||||||||
// Set our staking contracts | ||||||||||||||||||||||||||||||||||||||||||||||
inventoryStaking = INFTXInventoryStaking(_inventoryStaking); | ||||||||||||||||||||||||||||||||||||||||||||||
lpStaking = INFTXLPStaking(_lpStaking); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// Set our NFTX factory contract | ||||||||||||||||||||||||||||||||||||||||||||||
nftxFactory = INFTXVaultFactory(_nftxFactory); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// Set our Sushi Router used for liquidity | ||||||||||||||||||||||||||||||||||||||||||||||
sushiRouter = IUniswapV2Router01(_sushiRouter); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// Set our chain's WETH contract | ||||||||||||||||||||||||||||||||||||||||||||||
WETH = IWETH(_weth); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||
* @notice Allows the user to buy and stake tokens against an Inventory. This will | ||||||||||||||||||||||||||||||||||||||||||||||
* handle the purchase of the vault tokens against 0x and then generate the xToken | ||||||||||||||||||||||||||||||||||||||||||||||
* against the vault and timelock them. | ||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||
* @param vaultId The ID of the NFTX vault | ||||||||||||||||||||||||||||||||||||||||||||||
* @param swapCallData The `data` field from the 0x API response | ||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
function buyAndStakeInventory( | ||||||||||||||||||||||||||||||||||||||||||||||
uint256 vaultId, | ||||||||||||||||||||||||||||||||||||||||||||||
bytes calldata swapCallData | ||||||||||||||||||||||||||||||||||||||||||||||
) external payable nonReentrant { | ||||||||||||||||||||||||||||||||||||||||||||||
// Ensure we have tx value | ||||||||||||||||||||||||||||||||||||||||||||||
require(msg.value > 0, 'Invalid value provided'); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// Get our start WETH balance | ||||||||||||||||||||||||||||||||||||||||||||||
uint wethBalance = WETH.balanceOf(address(this)); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// Wrap ETH into WETH for our contract from the sender | ||||||||||||||||||||||||||||||||||||||||||||||
if (msg.value > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||
WETH.deposit{value: msg.value}(); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
// Get our vaults base staking token. This is used to calculate the xToken | ||||||||||||||||||||||||||||||||||||||||||||||
address baseToken = _vaultAddress(vaultId); | ||||||||||||||||||||||||||||||||||||||||||||||
require(baseToken != address(0), 'Invalid vault provided'); | ||||||||||||||||||||||||||||||||||||||||||||||
|
// Get our start WETH balance | |
uint wethBalance = WETH.balanceOf(address(this)); | |
// Wrap ETH into WETH for our contract from the sender | |
if (msg.value > 0) { | |
WETH.deposit{value: msg.value}(); | |
} | |
// Get our vaults base staking token. This is used to calculate the xToken | |
address baseToken = _vaultAddress(vaultId); | |
require(baseToken != address(0), 'Invalid vault provided'); | |
// Get our vaults base staking token. This is used to calculate the xToken | |
address baseToken = _vaultAddress(vaultId); | |
require(baseToken != address(0), 'Invalid vault provided'); | |
// Get our start WETH balance | |
uint wethBalance = WETH.balanceOf(address(this)); | |
// Wrap ETH into WETH for our contract from the sender | |
if (msg.value > 0) { | |
WETH.deposit{value: msg.value}(); | |
} |
Reorder for readability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No timelock is being applied here, is that ok?
0xKiwi marked this conversation as resolved.
Show resolved
Hide resolved
0xKiwi marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why this is needed when you can just use the factory no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mentioned briefly in previous comment, but it is for gas savings for repeat calls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have a rough estimate on savings?
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could malicious ownership allow this zap to perform the vulnerability?
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably revert so if anyone just randomly sends ETH it doesn't get stuck
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
|
||
contract MockSushiSwap { | ||
|
||
function addLiquidity( | ||
address tokenA, | ||
address tokenB, | ||
uint256 amountADesired, | ||
uint256 amountBDesired, | ||
uint256 amountAMin, | ||
uint256 amountBMin, | ||
address to, | ||
uint256 deadline | ||
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity) { | ||
amountA = 1; | ||
amountB = 1; | ||
liquidity = 1; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing this could allow any fee excluded address to unlimited mint any about of tokens
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I've added this back but altered the logic so that it looks in a mapping, rather than a single address match