-
Notifications
You must be signed in to change notification settings - Fork 2
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
Yashika Goyal
committed
Dec 21, 2023
1 parent
6fd5711
commit c67d962
Showing
7 changed files
with
680 additions
and
0 deletions.
There are no files selected for viewing
169 changes: 169 additions & 0 deletions
169
contracts/intent-adapters/liquid-staking/Frax/FraxStakeEth.sol
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,169 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.18; | ||
|
||
import {IFraxEthMinter} from "./Interfaces.sol"; | ||
import {RouterIntentAdapter, Errors} from "router-intents/contracts/RouterIntentAdapter.sol"; | ||
import {NitroMessageHandler} from "router-intents/contracts/NitroMessageHandler.sol"; | ||
import {IERC20, SafeERC20} from "../../../utils/SafeERC20.sol"; | ||
|
||
/** | ||
* @title FraxStakeEth | ||
* @author Yashika Goyal | ||
* @notice Staking ETH to receive fraxETH or stakedFraxETH on Frax. | ||
* @notice This contract is only for Ethereum chain. | ||
*/ | ||
contract FraxStakeEth is RouterIntentAdapter, NitroMessageHandler { | ||
using SafeERC20 for IERC20; | ||
|
||
IFraxEthMinter private immutable _fraxEthMinter; | ||
address private immutable _fraxEth; | ||
address private immutable _stakedFraxEth; | ||
|
||
event FraxStakeEthDest(address _recipient, address token, uint256 _returnAmount); | ||
|
||
error InvalidTxType(); | ||
|
||
constructor( | ||
address __native, | ||
address __wnative, | ||
address __owner, | ||
address __assetForwarder, | ||
address __dexspan, | ||
address __fraxEth, | ||
address __stakedFraxEth, | ||
address __fraxEthMinter | ||
) | ||
RouterIntentAdapter(__native, __wnative, __owner) | ||
NitroMessageHandler(__assetForwarder, __dexspan) | ||
{ | ||
_fraxEth = __fraxEth; | ||
_stakedFraxEth = __stakedFraxEth; | ||
_fraxEthMinter = IFraxEthMinter(__fraxEthMinter); | ||
} | ||
|
||
function fraxEth() public view returns (address) { | ||
return _fraxEth; | ||
} | ||
|
||
function stakedFraxEth() public view returns (address) { | ||
return _stakedFraxEth; | ||
} | ||
|
||
function fraxEthMinter() public view returns (IFraxEthMinter) { | ||
return _fraxEthMinter; | ||
} | ||
|
||
function name() public pure override returns (string memory) { | ||
return "FraxStakeEth"; | ||
} | ||
|
||
/** | ||
* @inheritdoc RouterIntentAdapter | ||
*/ | ||
function execute( | ||
address, | ||
address, | ||
bytes calldata data | ||
) external payable override returns (address[] memory tokens) { | ||
(address _recipient, uint256 _amount, uint256 _txType) = parseInputs(data); | ||
|
||
// If the adapter is called using `call` and not `delegatecall` | ||
if (address(this) == self()) { | ||
require( | ||
msg.value == _amount, | ||
Errors.INSUFFICIENT_NATIVE_FUNDS_PASSED | ||
); | ||
} | ||
|
||
bytes memory logData; | ||
|
||
(tokens, logData) = _stake(_recipient, _amount, _txType); | ||
|
||
emit ExecutionEvent(name(), logData); | ||
return tokens; | ||
} | ||
|
||
/** | ||
* @inheritdoc NitroMessageHandler | ||
*/ | ||
function handleMessage( | ||
address tokenSent, | ||
uint256 amount, | ||
bytes memory instruction | ||
) external override onlyNitro nonReentrant { | ||
(address recipient, uint256 txType) = abi.decode(instruction, (address, uint256)); | ||
|
||
if (tokenSent != native()) { | ||
withdrawTokens(tokenSent, recipient, amount); | ||
emit OperationFailedRefundEvent(tokenSent, recipient, amount); | ||
return; | ||
} | ||
|
||
if (txType == 1) { | ||
try _fraxEthMinter.submitAndGive{value: amount}(recipient) { | ||
emit FraxStakeEthDest(recipient, _fraxEth, amount); | ||
} catch { | ||
withdrawTokens(tokenSent, recipient, amount); | ||
emit OperationFailedRefundEvent(tokenSent, recipient, amount); | ||
} | ||
} else if (txType == 2) { | ||
try _fraxEthMinter.submitAndDeposit{value: amount}(recipient) | ||
returns (uint256 _receivedSFrxEth) { | ||
emit FraxStakeEthDest(recipient, _stakedFraxEth, _receivedSFrxEth); | ||
} catch { | ||
withdrawTokens(tokenSent, recipient, amount); | ||
emit OperationFailedRefundEvent(tokenSent, recipient, amount); | ||
} | ||
} else { | ||
revert InvalidTxType(); | ||
} | ||
} | ||
|
||
//////////////////////////// ACTION LOGIC //////////////////////////// | ||
|
||
/** | ||
* @notice function to stake funds on Frax ETH Pool. | ||
* @param _recipient address of the recipient. | ||
* @param _amount amount to be staked. | ||
* @param _txType Type of transaction. | ||
* 1 for staking Eth to get frxEth. | ||
* 2 for staking Eth and then staking frxEth to get sFrxEth. | ||
*/ | ||
|
||
function _stake( | ||
address _recipient, | ||
uint256 _amount, | ||
uint256 _txType | ||
) internal returns (address[] memory tokens, bytes memory logData) { | ||
if (_txType == 1) { | ||
_fraxEthMinter.submitAndGive{value: _amount}(_recipient); | ||
tokens = new address[](2); | ||
tokens[0] = native(); | ||
tokens[1] = fraxEth(); | ||
logData = abi.encode(_recipient, _fraxEth, _amount); | ||
|
||
} else if (_txType == 2) { | ||
uint256 _receivedSFrxEth = _fraxEthMinter.submitAndDeposit{value: _amount}(_recipient); | ||
tokens = new address[](2); | ||
tokens[0] = native(); | ||
tokens[1] = stakedFraxEth(); | ||
logData = abi.encode(_recipient, _stakedFraxEth, _receivedSFrxEth); | ||
|
||
} else { | ||
revert InvalidTxType(); | ||
} | ||
} | ||
|
||
/** | ||
* @dev function to parse input data. | ||
* @param data input data. | ||
*/ | ||
function parseInputs( | ||
bytes memory data | ||
) public pure returns (address, uint256, uint256) { | ||
return abi.decode(data, (address, uint256, uint256)); | ||
} | ||
|
||
// solhint-disable-next-line no-empty-blocks | ||
receive() external payable {} | ||
} |
10 changes: 10 additions & 0 deletions
10
contracts/intent-adapters/liquid-staking/Frax/Interfaces.sol
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,10 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.18; | ||
|
||
interface IFraxEthMinter { | ||
function submitAndDeposit( | ||
address recipient | ||
) external payable returns (uint256 shares); | ||
|
||
function submitAndGive(address recipient) external payable; | ||
} |
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,106 @@ | ||
import { HardhatRuntimeEnvironment, TaskArguments } from "hardhat/types"; | ||
import { | ||
ASSET_FORWARDER, | ||
CONTRACT_NAME, | ||
DEFAULT_ENV, | ||
DEFAULT_OWNER, | ||
DEFAULT_REFUND_ADDRESS, | ||
DEPLOY_FRAX_STAKE_ETH_ADAPTER, | ||
DEXSPAN, | ||
NATIVE, | ||
VERIFY_FRAX_STAKE_ETH_ADAPTER, | ||
WNATIVE, | ||
} from "../constants"; | ||
import { task } from "hardhat/config"; | ||
import { | ||
IDeployment, | ||
getDeployments, | ||
recordAllDeployments, | ||
saveDeployments, | ||
} from "../utils"; | ||
import { FRX_ETH, FRX_ETH_MINTER, S_FRX_ETH } from "./constants"; | ||
|
||
const contractName: string = CONTRACT_NAME.FraxStakeEth; | ||
|
||
task(DEPLOY_FRAX_STAKE_ETH_ADAPTER) | ||
.addFlag("verify", "pass true to verify the contract") | ||
.setAction(async function ( | ||
_taskArguments: TaskArguments, | ||
_hre: HardhatRuntimeEnvironment | ||
) { | ||
let env = process.env.ENV; | ||
if (!env) env = DEFAULT_ENV; | ||
|
||
let defaultRefundAddress = process.env.DEFAULT_REFUND_ADDRESS; | ||
if (!defaultRefundAddress) defaultRefundAddress = DEFAULT_REFUND_ADDRESS; | ||
|
||
let owner = process.env.OWNER; | ||
if (!owner) owner = DEFAULT_OWNER; | ||
|
||
const network = await _hre.getChainId(); | ||
|
||
console.log(`Deploying ${contractName} Contract on chainId ${network}....`); | ||
const factory = await _hre.ethers.getContractFactory(contractName); | ||
const instance = await factory.deploy( | ||
NATIVE, | ||
WNATIVE[env][network], | ||
owner, | ||
ASSET_FORWARDER[env][network], | ||
DEXSPAN[env][network], | ||
FRX_ETH[network], | ||
S_FRX_ETH[network], | ||
FRX_ETH_MINTER[network] | ||
); | ||
await instance.deployed(); | ||
|
||
const deployment: IDeployment = await recordAllDeployments( | ||
env, | ||
network, | ||
contractName, | ||
instance.address | ||
); | ||
|
||
await saveDeployments(deployment); | ||
|
||
console.log(`${contractName} contract deployed at`, instance.address); | ||
|
||
if (_taskArguments.verify === true) { | ||
await _hre.run(VERIFY_FRAX_STAKE_ETH_ADAPTER); | ||
} | ||
}); | ||
|
||
task(VERIFY_FRAX_STAKE_ETH_ADAPTER).setAction(async function ( | ||
_taskArguments: TaskArguments, | ||
_hre: HardhatRuntimeEnvironment | ||
) { | ||
let env = process.env.ENV; | ||
if (!env) env = DEFAULT_ENV; | ||
|
||
let defaultRefundAddress = process.env.DEFAULT_REFUND_ADDRESS; | ||
if (!defaultRefundAddress) defaultRefundAddress = DEFAULT_REFUND_ADDRESS; | ||
|
||
let owner = process.env.OWNER; | ||
if (!owner) owner = DEFAULT_OWNER; | ||
|
||
const network = await _hre.getChainId(); | ||
|
||
const deployments: IDeployment = getDeployments(); | ||
const address = deployments[env][network][contractName]; | ||
|
||
console.log(`Verifying ${contractName} Contract....`); | ||
await _hre.run("verify:verify", { | ||
address, | ||
constructorArguments: [ | ||
NATIVE, | ||
WNATIVE[env][network], | ||
owner, | ||
ASSET_FORWARDER[env][network], | ||
DEXSPAN[env][network], | ||
FRX_ETH[network], | ||
S_FRX_ETH[network], | ||
FRX_ETH_MINTER[network] | ||
], | ||
}); | ||
|
||
console.log(`Verified ${contractName} contract address `, address); | ||
}); |
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,11 @@ | ||
export const FRX_ETH_MINTER: { [chainId: string]: string } = { | ||
"1": "0xbAFA44EFE7901E04E39Dad13167D089C559c1138", | ||
}; | ||
|
||
export const FRX_ETH: { [chainId: string]: string } = { | ||
"1": "0x5E8422345238F34275888049021821E8E08CAa1f", | ||
}; | ||
|
||
export const S_FRX_ETH: { [chainId: string]: string } = { | ||
"1": "0xac3E018457B222d93114458476f3E3416Abbe38F", | ||
}; |
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 @@ | ||
import "./FraxStakeEth.deploy"; |
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
Oops, something went wrong.