-
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.
* update Euphrates * add DropAndSwapStakeRouter
- Loading branch information
1 parent
27de5b6
commit 9f2a39e
Showing
3 changed files
with
171 additions
and
1 deletion.
There are no files selected for viewing
Submodule Euphrates
updated
44 files
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,78 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.17; | ||
|
||
import { ERC20 } from "solmate/tokens/ERC20.sol"; | ||
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; | ||
import { FeeRegistry } from "./FeeRegistry.sol"; | ||
import { DropAndSwapStakeRouter, DropAndSwapStakeInstructions } from "./DropAndSwapStakeRouter.sol"; | ||
|
||
contract DropAndSwapStakeFactory { | ||
using SafeTransferLib for ERC20; | ||
|
||
function deployDropAndSwapStakeRouter( | ||
FeeRegistry fees, | ||
DropAndSwapStakeInstructions memory inst, | ||
uint256 dropAmount | ||
) public returns (DropAndSwapStakeRouter) { | ||
require( | ||
inst.recipient != address(0) && inst.feeReceiver != address(0) && address(inst.dropToken) != address(0) | ||
&& inst.euphrates != address(0), | ||
"invalid inst" | ||
); | ||
|
||
// no need to use salt as we want to keep the router address the same for the same fees &instructions | ||
bytes32 salt; | ||
|
||
DropAndSwapStakeRouter router; | ||
try new DropAndSwapStakeRouter{salt: salt}(fees, inst) returns (DropAndSwapStakeRouter router_) { | ||
router = router_; | ||
} catch { | ||
router = DropAndSwapStakeRouter( | ||
address( | ||
uint160( | ||
uint256( | ||
keccak256( | ||
abi.encodePacked( | ||
bytes1(0xff), | ||
address(this), | ||
salt, | ||
keccak256( | ||
abi.encodePacked( | ||
type(DropAndSwapStakeRouter).creationCode, abi.encode(fees, inst) | ||
) | ||
) | ||
) | ||
) | ||
) | ||
) | ||
) | ||
); | ||
} | ||
|
||
if (dropAmount > 0) { | ||
inst.dropToken.safeTransferFrom(msg.sender, address(router), dropAmount); | ||
} | ||
|
||
return router; | ||
} | ||
|
||
function deployDropAndSwapStakeRouterAndRoute( | ||
FeeRegistry fees, | ||
DropAndSwapStakeInstructions memory inst, | ||
ERC20 token, | ||
uint256 dropAmount | ||
) public { | ||
DropAndSwapStakeRouter router = deployDropAndSwapStakeRouter(fees, inst, dropAmount); | ||
router.route(token, msg.sender); | ||
} | ||
|
||
function deployDropAndSwapStakeRouterAndRouteNoFee( | ||
FeeRegistry fees, | ||
DropAndSwapStakeInstructions memory inst, | ||
ERC20 token, | ||
uint256 dropAmount | ||
) public { | ||
DropAndSwapStakeRouter router = deployDropAndSwapStakeRouter(fees, inst, dropAmount); | ||
router.routeNoFee(token); | ||
} | ||
} |
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,92 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.17; | ||
|
||
import { ERC20 } from "solmate/tokens/ERC20.sol"; | ||
import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; | ||
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; | ||
import { IDEX } from "@acala-network/contracts/dex/IDEX.sol"; | ||
import { IStakingTo } from "euphrates/IStaking.sol"; | ||
|
||
import { BaseRouter } from "./BaseRouter.sol"; | ||
import { FeeRegistry } from "./FeeRegistry.sol"; | ||
|
||
struct DropAndSwapStakeInstructions { | ||
address recipient; | ||
uint256 dropFee; | ||
address feeReceiver; | ||
ERC20 dropToken; | ||
address dex; | ||
uint256 swapAmount; | ||
address[] path; | ||
address euphrates; | ||
uint256 poolId; | ||
uint256 minShareAmount; | ||
} | ||
|
||
contract DropAndSwapStakeRouter is BaseRouter { | ||
using SafeTransferLib for ERC20; | ||
|
||
DropAndSwapStakeInstructions private _instructions; | ||
|
||
constructor(FeeRegistry fees, DropAndSwapStakeInstructions memory instructions) BaseRouter(fees) { | ||
_instructions = instructions; | ||
} | ||
|
||
function routeImpl(ERC20 token) internal override { | ||
if (token.balanceOf(address(this)) < _instructions.dropFee) { | ||
revert("DropAndStakeByDEXUtilRouter: cannot afford drop fee"); | ||
} | ||
token.safeTransfer(_instructions.feeReceiver, _instructions.dropFee); | ||
|
||
require( | ||
_instructions.path.length >= 2 && _instructions.path[0] == address(token), | ||
"DropAndStakeByDEXUtilRouter: invalid path" | ||
); | ||
address targetToken = _instructions.path[_instructions.path.length - 1]; | ||
address lpToken = IDEX(_instructions.dex).getLiquidityTokenAddress(address(token), address(targetToken)); | ||
|
||
require(lpToken != address(0), "DropAndStakeByDEXUtilRouter: liquidity pool not exist"); | ||
require( | ||
lpToken == address(IStakingTo(_instructions.euphrates).shareTypes(_instructions.poolId)), | ||
"DropAndStakeByDEXUtilRouter: share token is not matched the lp token" | ||
); | ||
|
||
token.safeApprove(_instructions.dex, _instructions.swapAmount); | ||
bool swapResult = IDEX(_instructions.dex).swapWithExactSupply(_instructions.path, _instructions.swapAmount, 0); | ||
require(swapResult, "DropAndStakeByDEXUtilRouter: swap failed"); | ||
|
||
// no need to approve, IDEX transfer from directly | ||
bool addLiquidityResult = IDEX(_instructions.dex).addLiquidity( | ||
address(token), | ||
targetToken, | ||
token.balanceOf(address(this)), | ||
ERC20(targetToken).balanceOf(address(this)), | ||
_instructions.minShareAmount | ||
); | ||
require(addLiquidityResult, "DropAndStakeByDEXUtilRouter: addLiquidity failed"); | ||
|
||
ERC20(lpToken).safeApprove(_instructions.euphrates, ERC20(lpToken).balanceOf(address(this))); | ||
bool stakeResult = IStakingTo(_instructions.euphrates).stakeTo( | ||
_instructions.poolId, ERC20(lpToken).balanceOf(address(this)), _instructions.recipient | ||
); | ||
require(stakeResult, "DropAndStakeByDEXUtilRouter: stake failed"); | ||
|
||
// return remain assets | ||
token.safeTransfer(_instructions.recipient, token.balanceOf(address(this))); | ||
ERC20(targetToken).safeTransfer(_instructions.recipient, ERC20(targetToken).balanceOf(address(this))); | ||
|
||
// transfer all dropToken to recipient | ||
_instructions.dropToken.safeTransfer(_instructions.recipient, _instructions.dropToken.balanceOf(address(this))); | ||
} | ||
|
||
function rescure(ERC20 token) public { | ||
// transfer dropFee to feeReceiver if possible | ||
token.safeTransfer(_instructions.feeReceiver, Math.min(_instructions.dropFee, token.balanceOf(address(this)))); | ||
|
||
// transfer it to recipient to avoid it stuck in this contract | ||
token.safeTransfer(_instructions.recipient, token.balanceOf(address(this))); | ||
|
||
// transfer all dropToken to recipient | ||
_instructions.dropToken.safeTransfer(_instructions.recipient, _instructions.dropToken.balanceOf(address(this))); | ||
} | ||
} |