Skip to content

Commit

Permalink
feat: added frax adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
Yashika Goyal committed Dec 21, 2023
1 parent 6fd5711 commit c67d962
Show file tree
Hide file tree
Showing 7 changed files with 680 additions and 0 deletions.
169 changes: 169 additions & 0 deletions contracts/intent-adapters/liquid-staking/Frax/FraxStakeEth.sol
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 contracts/intent-adapters/liquid-staking/Frax/Interfaces.sol
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;
}
106 changes: 106 additions & 0 deletions tasks/frax/FraxStakeEth.deploy.ts
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);
});
11 changes: 11 additions & 0 deletions tasks/frax/constants.ts
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",
};
1 change: 1 addition & 0 deletions tasks/frax/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./FraxStakeEth.deploy";
1 change: 1 addition & 0 deletions tasks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "./rocketPool";
import "./swell";
import "./synClub";
import "./metaPool";
import "./frax";
import "./dexspan";
import "./erc20";
import "./uniswapV3";
Expand Down
Loading

0 comments on commit c67d962

Please sign in to comment.