2022-01-23 06:40:27 -08:00
|
|
|
// SPDX-License-Identifier: Apache 2
|
|
|
|
|
2022-01-11 08:29:49 -08:00
|
|
|
pragma solidity ^0.7.6;
|
|
|
|
pragma abicoder v2;
|
|
|
|
|
2022-06-30 14:49:49 -07:00
|
|
|
import './shared/IWormhole.sol';
|
|
|
|
import './shared/SwapHelper.sol';
|
|
|
|
import './shared/TokenBridge.sol';
|
|
|
|
import './shared/WETH.sol';
|
2022-01-20 13:40:38 -08:00
|
|
|
import 'solidity-bytes-utils/contracts/BytesLib.sol';
|
|
|
|
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
|
|
|
|
import '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
|
|
|
|
import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';
|
|
|
|
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
|
2022-01-11 08:29:49 -08:00
|
|
|
|
|
|
|
|
2022-01-22 11:25:01 -08:00
|
|
|
/// @title A cross-chain UniswapV2 example
|
|
|
|
/// @notice Swaps against UniswapV2 pools and uses Wormhole TokenBridge
|
|
|
|
/// for cross-chain transfers
|
2022-01-11 08:29:49 -08:00
|
|
|
contract CrossChainSwapV2 {
|
|
|
|
using SafeERC20 for IERC20;
|
|
|
|
using BytesLib for bytes;
|
2022-06-30 14:49:49 -07:00
|
|
|
uint8 public immutable TypeExactIn = 1;
|
|
|
|
uint8 public immutable TypeExactOut = 2;
|
|
|
|
IUniswapV2Router02 public immutable SWAP_ROUTER;
|
|
|
|
address public immutable FEE_TOKEN_ADDRESS;
|
|
|
|
address public immutable TOKEN_BRIDGE_ADDRESS;
|
|
|
|
address public immutable WRAPPED_NATIVE;
|
2022-01-20 08:52:35 -08:00
|
|
|
|
|
|
|
constructor(
|
|
|
|
address _swapRouterAddress,
|
|
|
|
address _feeTokenAddress,
|
|
|
|
address _tokenBridgeAddress,
|
2022-01-21 10:37:14 -08:00
|
|
|
address _wrappedNativeAddress
|
2022-01-20 08:52:35 -08:00
|
|
|
) {
|
2022-06-30 14:49:49 -07:00
|
|
|
SWAP_ROUTER = IUniswapV2Router02(_swapRouterAddress);
|
|
|
|
FEE_TOKEN_ADDRESS = _feeTokenAddress;
|
|
|
|
TOKEN_BRIDGE_ADDRESS = _tokenBridgeAddress;
|
|
|
|
WRAPPED_NATIVE = _wrappedNativeAddress;
|
2022-01-20 08:52:35 -08:00
|
|
|
}
|
|
|
|
|
2022-01-22 11:25:01 -08:00
|
|
|
/// @dev Used to communicate information about executed swaps to UI/user
|
2022-01-20 13:40:38 -08:00
|
|
|
event SwapResult(
|
2022-01-21 10:37:14 -08:00
|
|
|
address indexed _recipient,
|
|
|
|
address _tokenOut,
|
|
|
|
address _from,
|
|
|
|
uint256 _amountOut,
|
|
|
|
uint8 _success
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
|
|
|
|
2022-01-22 11:25:01 -08:00
|
|
|
/// @dev Returns the parsed TokenBridge payload which contains swap
|
|
|
|
/// instructions after redeeming the VAA from the TokenBridge
|
2022-01-20 13:40:38 -08:00
|
|
|
function _getParsedPayload(
|
|
|
|
bytes calldata encodedVaa,
|
2022-06-30 14:49:49 -07:00
|
|
|
uint8 swapFunctionType
|
2022-01-20 13:40:38 -08:00
|
|
|
) private returns (SwapHelper.DecodedVaaParameters memory payload) {
|
2022-01-20 08:52:35 -08:00
|
|
|
// complete the transfer on the token bridge
|
2022-03-23 14:33:25 -07:00
|
|
|
bytes memory vmPayload = TokenBridge(
|
2022-06-30 14:49:49 -07:00
|
|
|
TOKEN_BRIDGE_ADDRESS
|
2022-06-28 16:03:50 -07:00
|
|
|
).completeTransferWithPayload(encodedVaa);
|
2022-01-20 08:52:35 -08:00
|
|
|
|
|
|
|
// parse the payload
|
2022-03-23 14:33:25 -07:00
|
|
|
payload = SwapHelper.decodeVaaPayload(vmPayload);
|
2022-01-20 13:40:38 -08:00
|
|
|
|
|
|
|
// sanity check payload parameters
|
|
|
|
require(
|
|
|
|
payload.swapFunctionType==swapFunctionType,
|
2022-01-22 11:25:01 -08:00
|
|
|
"incorrect swapFunctionType in payload"
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-01-22 11:25:01 -08:00
|
|
|
/// @dev Executes exactIn native asset swap and pays the relayer
|
2022-01-20 13:40:38 -08:00
|
|
|
function recvAndSwapExactNativeIn(
|
|
|
|
bytes calldata encodedVaa
|
|
|
|
) external payable returns (uint256[] memory amounts) {
|
|
|
|
// redeem and fetch parsed payload
|
|
|
|
SwapHelper.DecodedVaaParameters memory payload =
|
|
|
|
_getParsedPayload(
|
|
|
|
encodedVaa,
|
2022-06-30 14:49:49 -07:00
|
|
|
TypeExactIn
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
2022-01-20 08:52:35 -08:00
|
|
|
|
2022-01-22 11:25:01 -08:00
|
|
|
// create dynamic address array
|
|
|
|
// uniswap won't take fixed size array
|
2022-01-20 08:52:35 -08:00
|
|
|
address[] memory uniPath = new address[](2);
|
|
|
|
uniPath[0] = payload.path[0];
|
|
|
|
uniPath[1] = payload.path[1];
|
2022-01-22 11:25:01 -08:00
|
|
|
|
|
|
|
// sanity check path
|
|
|
|
require(
|
2022-06-30 14:49:49 -07:00
|
|
|
uniPath[0]==FEE_TOKEN_ADDRESS,
|
|
|
|
"tokenIn must be feeToken"
|
2022-01-22 11:25:01 -08:00
|
|
|
);
|
2022-01-21 10:37:14 -08:00
|
|
|
require(
|
2022-06-30 14:49:49 -07:00
|
|
|
uniPath[1]==WRAPPED_NATIVE,
|
2022-01-21 10:37:14 -08:00
|
|
|
"tokenOut must be wrapped native asset"
|
|
|
|
);
|
2022-01-20 08:52:35 -08:00
|
|
|
|
|
|
|
// approve the router to spend tokens
|
2022-01-20 13:40:38 -08:00
|
|
|
TransferHelper.safeApprove(
|
|
|
|
uniPath[0],
|
2022-06-30 14:49:49 -07:00
|
|
|
address(SWAP_ROUTER),
|
2022-07-01 10:52:56 -07:00
|
|
|
payload.swapAmount
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
2022-01-20 08:52:35 -08:00
|
|
|
|
2022-01-21 10:37:14 -08:00
|
|
|
// try to execute the swap
|
2022-06-30 14:49:49 -07:00
|
|
|
try SWAP_ROUTER.swapExactTokensForTokens(
|
2022-07-01 10:52:56 -07:00
|
|
|
payload.swapAmount,
|
2022-01-20 08:52:35 -08:00
|
|
|
payload.estimatedAmount,
|
|
|
|
uniPath,
|
2022-01-20 13:40:38 -08:00
|
|
|
address(this),
|
2022-01-20 08:52:35 -08:00
|
|
|
payload.deadline
|
|
|
|
) returns (uint256[] memory amounts) {
|
2022-07-01 10:52:56 -07:00
|
|
|
// calculate how much to pay the relayer in the native token
|
|
|
|
uint256 nativeRelayerFee = amounts[1] * payload.relayerFee / payload.swapAmount;
|
|
|
|
uint256 nativeAmountOut = amounts[1] - nativeRelayerFee;
|
|
|
|
|
2022-01-20 13:40:38 -08:00
|
|
|
// unwrap native and send to recipient
|
2022-06-30 14:49:49 -07:00
|
|
|
IWETH(WRAPPED_NATIVE).withdraw(amounts[1]);
|
2022-07-01 10:52:56 -07:00
|
|
|
payable(payload.recipientAddress).transfer(nativeAmountOut);
|
|
|
|
|
|
|
|
/// pay the relayer in the native token
|
|
|
|
payable(msg.sender).transfer(nativeRelayerFee);
|
2022-01-20 13:40:38 -08:00
|
|
|
|
|
|
|
// used in UI to tell user they're getting
|
|
|
|
// their desired token
|
|
|
|
emit SwapResult(
|
|
|
|
payload.recipientAddress,
|
|
|
|
uniPath[1],
|
|
|
|
msg.sender,
|
2022-07-01 10:52:56 -07:00
|
|
|
nativeAmountOut,
|
2022-01-21 10:37:14 -08:00
|
|
|
1
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
2022-01-20 08:52:35 -08:00
|
|
|
return amounts;
|
|
|
|
} catch {
|
2022-07-01 10:52:56 -07:00
|
|
|
// pay relayer in the feeToken since the swap failed
|
|
|
|
IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS);
|
|
|
|
feeToken.safeTransfer(msg.sender, payload.relayerFee);
|
|
|
|
|
2022-06-30 14:49:49 -07:00
|
|
|
// swap failed - return feeToken to recipient
|
2022-07-01 10:52:56 -07:00
|
|
|
feeToken.safeTransfer(
|
2022-01-20 13:40:38 -08:00
|
|
|
payload.recipientAddress,
|
2022-07-01 10:52:56 -07:00
|
|
|
payload.swapAmount - payload.relayerFee
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// used in UI to tell user they're getting
|
2022-06-30 14:49:49 -07:00
|
|
|
// feeToken instead of their desired native asset
|
2022-01-20 13:40:38 -08:00
|
|
|
emit SwapResult(
|
|
|
|
payload.recipientAddress,
|
|
|
|
uniPath[0],
|
|
|
|
msg.sender,
|
2022-07-01 10:52:56 -07:00
|
|
|
payload.swapAmount - payload.relayerFee,
|
2022-01-21 10:37:14 -08:00
|
|
|
0
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
2022-01-20 08:52:35 -08:00
|
|
|
}
|
2022-01-11 08:29:49 -08:00
|
|
|
}
|
|
|
|
|
2022-06-28 16:03:50 -07:00
|
|
|
/// @dev Executes exactOut native asset swap and pays the relayer
|
|
|
|
function recvAndSwapExactNativeOut(
|
2022-01-11 08:29:49 -08:00
|
|
|
bytes calldata encodedVaa
|
2022-06-28 16:03:50 -07:00
|
|
|
) external returns (uint256 amountInUsed) {
|
|
|
|
// redeem and fetch parsed payload
|
2022-01-20 13:40:38 -08:00
|
|
|
SwapHelper.DecodedVaaParameters memory payload =
|
|
|
|
_getParsedPayload(
|
|
|
|
encodedVaa,
|
2022-06-30 14:49:49 -07:00
|
|
|
TypeExactOut
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
2022-01-11 08:29:49 -08:00
|
|
|
|
|
|
|
// create dynamic address array - uniswap won't take fixed size array
|
|
|
|
address[] memory uniPath = new address[](2);
|
|
|
|
uniPath[0] = payload.path[0];
|
|
|
|
uniPath[1] = payload.path[1];
|
2022-01-22 11:25:01 -08:00
|
|
|
|
2022-06-28 16:03:50 -07:00
|
|
|
// sanity check path
|
|
|
|
require(
|
2022-06-30 14:49:49 -07:00
|
|
|
uniPath[0]==FEE_TOKEN_ADDRESS,
|
|
|
|
"tokenIn must be feeToken"
|
2022-06-28 16:03:50 -07:00
|
|
|
);
|
|
|
|
require(
|
2022-06-30 14:49:49 -07:00
|
|
|
payload.path[1]==WRAPPED_NATIVE,
|
2022-06-28 16:03:50 -07:00
|
|
|
"tokenOut must be wrapped native asset"
|
|
|
|
);
|
|
|
|
|
2022-07-01 10:52:56 -07:00
|
|
|
// pay the relayer in feeToken so that user gets desired exact amount out
|
2022-06-30 14:49:49 -07:00
|
|
|
IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS);
|
2022-06-28 16:03:50 -07:00
|
|
|
feeToken.safeTransfer(msg.sender, payload.relayerFee);
|
|
|
|
uint256 maxAmountInLessFees = payload.swapAmount - payload.relayerFee;
|
|
|
|
|
|
|
|
// amountOut is the estimated swap amount for exact out methods
|
|
|
|
uint256 amountOut = payload.estimatedAmount;
|
2022-01-11 08:29:49 -08:00
|
|
|
|
|
|
|
// approve the router to spend tokens
|
2022-01-20 13:40:38 -08:00
|
|
|
TransferHelper.safeApprove(
|
|
|
|
uniPath[0],
|
2022-06-30 14:49:49 -07:00
|
|
|
address(SWAP_ROUTER),
|
2022-06-28 16:03:50 -07:00
|
|
|
maxAmountInLessFees
|
|
|
|
);
|
2022-01-11 08:29:49 -08:00
|
|
|
|
2022-06-28 16:03:50 -07:00
|
|
|
// try to perform the swap
|
2022-06-30 14:49:49 -07:00
|
|
|
try SWAP_ROUTER.swapTokensForExactTokens(
|
2022-06-28 16:03:50 -07:00
|
|
|
amountOut,
|
|
|
|
maxAmountInLessFees,
|
2022-01-11 08:29:49 -08:00
|
|
|
uniPath,
|
2022-06-28 16:03:50 -07:00
|
|
|
address(this),
|
2022-01-11 08:29:49 -08:00
|
|
|
payload.deadline
|
|
|
|
) returns (uint256[] memory amounts) {
|
2022-06-28 16:03:50 -07:00
|
|
|
// amountIn used is first element in array
|
|
|
|
amountInUsed = amounts[0];
|
|
|
|
|
2022-06-30 14:49:49 -07:00
|
|
|
// refund recipient with any feeToken not used in the swap
|
2022-06-28 16:03:50 -07:00
|
|
|
if (amountInUsed < maxAmountInLessFees) {
|
|
|
|
TransferHelper.safeApprove(
|
2022-06-30 14:49:49 -07:00
|
|
|
FEE_TOKEN_ADDRESS,
|
|
|
|
address(SWAP_ROUTER),
|
2022-06-28 16:03:50 -07:00
|
|
|
0
|
|
|
|
);
|
2022-06-30 14:49:49 -07:00
|
|
|
IERC20(FEE_TOKEN_ADDRESS).safeTransfer(
|
2022-06-28 16:03:50 -07:00
|
|
|
payload.recipientAddress,
|
|
|
|
maxAmountInLessFees - amountInUsed
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// unwrap native and send to recipient
|
2022-06-30 14:49:49 -07:00
|
|
|
IWETH(WRAPPED_NATIVE).withdraw(amounts[1]);
|
2022-06-28 16:03:50 -07:00
|
|
|
payable(payload.recipientAddress).transfer(amounts[1]);
|
|
|
|
|
2022-01-20 13:40:38 -08:00
|
|
|
// used in UI to tell user they're getting
|
2022-06-28 16:03:50 -07:00
|
|
|
// their desired native asset
|
2022-01-20 13:40:38 -08:00
|
|
|
emit SwapResult(
|
|
|
|
payload.recipientAddress,
|
|
|
|
uniPath[1],
|
|
|
|
msg.sender,
|
2022-01-21 10:37:14 -08:00
|
|
|
amounts[1],
|
|
|
|
1
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
2022-06-28 16:03:50 -07:00
|
|
|
return amountInUsed;
|
2022-01-11 08:29:49 -08:00
|
|
|
} catch {
|
2022-06-30 14:49:49 -07:00
|
|
|
// swap failed - return feeToken to recipient
|
|
|
|
IERC20(FEE_TOKEN_ADDRESS).safeTransfer(
|
2022-01-20 13:40:38 -08:00
|
|
|
payload.recipientAddress,
|
2022-06-28 16:03:50 -07:00
|
|
|
maxAmountInLessFees
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
2022-01-22 11:25:01 -08:00
|
|
|
|
2022-01-20 13:40:38 -08:00
|
|
|
// used in UI to tell user they're getting
|
2022-06-30 14:49:49 -07:00
|
|
|
// feeToken instead of their desired native asset
|
2022-01-20 13:40:38 -08:00
|
|
|
emit SwapResult(
|
|
|
|
payload.recipientAddress,
|
|
|
|
uniPath[0],
|
|
|
|
msg.sender,
|
2022-06-28 16:03:50 -07:00
|
|
|
maxAmountInLessFees,
|
2022-01-21 10:37:14 -08:00
|
|
|
0
|
2022-01-20 13:40:38 -08:00
|
|
|
);
|
2022-06-28 16:03:50 -07:00
|
|
|
}
|
2022-01-11 08:29:49 -08:00
|
|
|
}
|
|
|
|
|
2022-06-28 16:03:50 -07:00
|
|
|
|
2022-06-30 14:49:49 -07:00
|
|
|
/// @dev Executes exactIn native asset swap
|
2022-01-11 08:29:49 -08:00
|
|
|
function _swapExactInBeforeTransfer(
|
|
|
|
uint256 amountIn,
|
|
|
|
uint256 amountOutMinimum,
|
|
|
|
address contractCaller,
|
|
|
|
address[] calldata path,
|
|
|
|
uint256 deadline
|
|
|
|
) internal returns (uint256 amountOut) {
|
|
|
|
// approve the router to spend tokens
|
2022-01-21 10:37:14 -08:00
|
|
|
TransferHelper.safeApprove(
|
|
|
|
path[0],
|
2022-06-30 14:49:49 -07:00
|
|
|
address(SWAP_ROUTER),
|
2022-01-21 10:37:14 -08:00
|
|
|
amountIn
|
|
|
|
);
|
2022-01-11 08:29:49 -08:00
|
|
|
|
|
|
|
// perform the swap
|
2022-06-30 14:49:49 -07:00
|
|
|
uint256[] memory amounts = SWAP_ROUTER.swapExactTokensForTokens(
|
2022-01-11 08:29:49 -08:00
|
|
|
amountIn,
|
|
|
|
amountOutMinimum,
|
|
|
|
path,
|
|
|
|
address(this),
|
|
|
|
deadline
|
|
|
|
);
|
|
|
|
amountOut = amounts[1];
|
|
|
|
}
|
|
|
|
|
2022-01-22 11:25:01 -08:00
|
|
|
/// @dev Calls _swapExactInBeforeTransfer and encodes custom payload with
|
|
|
|
/// instructions for executing native asset swaps on the destination chain
|
2022-01-20 13:40:38 -08:00
|
|
|
function swapExactNativeInAndTransfer(
|
2022-01-20 08:52:35 -08:00
|
|
|
SwapHelper.ExactInParameters calldata swapParams,
|
|
|
|
address[] calldata path,
|
|
|
|
uint256 relayerFee,
|
|
|
|
uint16 targetChainId,
|
|
|
|
bytes32 targetContractAddress,
|
|
|
|
uint32 nonce
|
|
|
|
) external payable {
|
2022-01-21 10:37:14 -08:00
|
|
|
require(
|
|
|
|
swapParams.amountOutMinimum > relayerFee,
|
|
|
|
"insufficient amountOutMinimum to pay relayer"
|
|
|
|
);
|
|
|
|
require(
|
2022-06-30 14:49:49 -07:00
|
|
|
path[0]==WRAPPED_NATIVE,
|
2022-01-21 10:37:14 -08:00
|
|
|
"tokenIn must be wrapped native asset for first swap"
|
|
|
|
);
|
|
|
|
require(
|
2022-06-30 14:49:49 -07:00
|
|
|
path[1]==FEE_TOKEN_ADDRESS,
|
|
|
|
"tokenOut must be feeToken for first swap"
|
2022-01-21 10:37:14 -08:00
|
|
|
);
|
|
|
|
require(msg.value > 0, "must pass non 0 native asset amount");
|
2022-01-20 08:52:35 -08:00
|
|
|
|
2022-01-21 10:37:14 -08:00
|
|
|
// wrap native asset
|
2022-06-30 14:49:49 -07:00
|
|
|
IWETH(WRAPPED_NATIVE).deposit{
|
2022-01-20 08:52:35 -08:00
|
|
|
value : msg.value
|
|
|
|
}();
|
|
|
|
|
|
|
|
// peform the first swap
|
|
|
|
uint256 amountOut = _swapExactInBeforeTransfer(
|
2022-01-22 11:25:01 -08:00
|
|
|
msg.value,
|
2022-01-20 08:52:35 -08:00
|
|
|
swapParams.amountOutMinimum,
|
|
|
|
msg.sender,
|
|
|
|
path[0:2],
|
|
|
|
swapParams.deadline
|
|
|
|
);
|
|
|
|
|
2022-06-28 16:03:50 -07:00
|
|
|
// create payload with target swap instructions
|
|
|
|
bytes memory payload = abi.encodePacked(
|
|
|
|
swapParams.targetAmountOutMinimum,
|
|
|
|
swapParams.targetChainRecipient,
|
|
|
|
path[2],
|
|
|
|
path[3],
|
|
|
|
swapParams.deadline,
|
|
|
|
swapParams.poolFee,
|
2022-06-30 14:49:49 -07:00
|
|
|
TypeExactIn,
|
2022-06-28 16:03:50 -07:00
|
|
|
relayerFee
|
|
|
|
);
|
|
|
|
|
2022-06-30 14:49:49 -07:00
|
|
|
// approve token bridge to spend feeTokens
|
2022-01-21 10:37:14 -08:00
|
|
|
TransferHelper.safeApprove(
|
2022-06-30 14:49:49 -07:00
|
|
|
FEE_TOKEN_ADDRESS,
|
|
|
|
TOKEN_BRIDGE_ADDRESS,
|
2022-01-21 10:37:14 -08:00
|
|
|
amountOut
|
|
|
|
);
|
2022-01-11 08:29:49 -08:00
|
|
|
|
|
|
|
// send transfer with payload to the TokenBridge
|
2022-06-30 14:49:49 -07:00
|
|
|
TokenBridge(TOKEN_BRIDGE_ADDRESS).transferTokensWithPayload(
|
|
|
|
FEE_TOKEN_ADDRESS,
|
2022-01-21 10:37:14 -08:00
|
|
|
amountOut,
|
|
|
|
targetChainId,
|
2022-06-28 16:03:50 -07:00
|
|
|
targetContractAddress,
|
2022-01-21 10:37:14 -08:00
|
|
|
nonce,
|
|
|
|
payload
|
2022-01-11 08:29:49 -08:00
|
|
|
);
|
|
|
|
}
|
2022-06-28 16:03:50 -07:00
|
|
|
|
2022-06-30 14:49:49 -07:00
|
|
|
/// @dev Executes exactOut native asset swaps
|
2022-01-11 08:29:49 -08:00
|
|
|
function _swapExactOutBeforeTransfer(
|
|
|
|
uint256 amountOut,
|
|
|
|
uint256 amountInMaximum,
|
|
|
|
address contractCaller,
|
|
|
|
address[] calldata path,
|
2022-06-30 14:49:49 -07:00
|
|
|
uint256 deadline
|
2022-01-22 11:25:01 -08:00
|
|
|
) internal {
|
2022-01-11 08:29:49 -08:00
|
|
|
// approve the router to spend tokens
|
2022-01-21 10:37:14 -08:00
|
|
|
TransferHelper.safeApprove(
|
|
|
|
path[0],
|
2022-06-30 14:49:49 -07:00
|
|
|
address(SWAP_ROUTER),
|
2022-01-21 10:37:14 -08:00
|
|
|
amountInMaximum
|
|
|
|
);
|
2022-01-11 08:29:49 -08:00
|
|
|
|
|
|
|
// perform the swap
|
2022-06-30 14:49:49 -07:00
|
|
|
uint256[] memory amounts = SWAP_ROUTER.swapTokensForExactTokens(
|
2022-01-11 08:29:49 -08:00
|
|
|
amountOut,
|
|
|
|
amountInMaximum,
|
|
|
|
path,
|
|
|
|
address(this),
|
|
|
|
deadline
|
|
|
|
);
|
|
|
|
|
|
|
|
// amountIn used is first element in array
|
|
|
|
uint256 amountInUsed = amounts[0];
|
|
|
|
|
|
|
|
// refund contractCaller with any amountIn that wasn't spent
|
|
|
|
if (amountInUsed < amountInMaximum) {
|
2022-06-30 14:49:49 -07:00
|
|
|
// unwrap remaining native asset and send to contractCaller
|
|
|
|
TransferHelper.safeApprove(path[0], address(SWAP_ROUTER), 0);
|
|
|
|
IWETH(WRAPPED_NATIVE).withdraw(
|
|
|
|
amountInMaximum - amountInUsed
|
|
|
|
);
|
|
|
|
payable(contractCaller).transfer(
|
|
|
|
amountInMaximum - amountInUsed
|
|
|
|
);
|
2022-01-11 08:29:49 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-22 11:25:01 -08:00
|
|
|
/// @dev Calls _swapExactOutBeforeTransfer and encodes custom payload with
|
|
|
|
/// instructions for executing native asset swaps on the destination chain
|
2022-01-20 13:40:38 -08:00
|
|
|
function swapExactNativeOutAndTransfer(
|
2022-01-20 08:52:35 -08:00
|
|
|
SwapHelper.ExactOutParameters calldata swapParams,
|
|
|
|
address[] calldata path,
|
|
|
|
uint256 relayerFee,
|
|
|
|
uint16 targetChainId,
|
|
|
|
bytes32 targetContractAddress,
|
|
|
|
uint32 nonce
|
|
|
|
) external payable {
|
2022-01-21 10:37:14 -08:00
|
|
|
require(
|
|
|
|
swapParams.amountOut > relayerFee,
|
|
|
|
"insufficient amountOut to pay relayer"
|
|
|
|
);
|
|
|
|
require(
|
2022-06-30 14:49:49 -07:00
|
|
|
path[0]==WRAPPED_NATIVE,
|
2022-01-21 10:37:14 -08:00
|
|
|
"tokenIn must be wrapped native asset for first swap"
|
|
|
|
);
|
|
|
|
require(
|
2022-06-30 14:49:49 -07:00
|
|
|
path[1]==FEE_TOKEN_ADDRESS,
|
|
|
|
"tokenOut must be feeToken for first swap"
|
2022-01-21 10:37:14 -08:00
|
|
|
);
|
|
|
|
require(msg.value > 0, "must pass non 0 native asset amount");
|
2022-01-20 08:52:35 -08:00
|
|
|
|
2022-01-21 10:37:14 -08:00
|
|
|
// wrap native asset
|
2022-06-30 14:49:49 -07:00
|
|
|
IWETH(WRAPPED_NATIVE).deposit{
|
2022-01-20 08:52:35 -08:00
|
|
|
value : msg.value
|
|
|
|
}();
|
|
|
|
|
|
|
|
// peform the first swap
|
2022-01-20 13:40:38 -08:00
|
|
|
_swapExactOutBeforeTransfer(
|
2022-01-20 08:52:35 -08:00
|
|
|
swapParams.amountOut,
|
2022-01-22 11:25:01 -08:00
|
|
|
msg.value,
|
2022-01-20 08:52:35 -08:00
|
|
|
msg.sender,
|
|
|
|
path[0:2],
|
2022-06-30 14:49:49 -07:00
|
|
|
swapParams.deadline
|
2022-01-20 08:52:35 -08:00
|
|
|
);
|
|
|
|
|
2022-06-28 16:03:50 -07:00
|
|
|
// create payload with target swap instructions
|
|
|
|
bytes memory payload = abi.encodePacked(
|
|
|
|
swapParams.targetAmountOut,
|
|
|
|
swapParams.targetChainRecipient,
|
|
|
|
path[2],
|
|
|
|
path[3],
|
|
|
|
swapParams.deadline,
|
|
|
|
swapParams.poolFee,
|
2022-06-30 14:49:49 -07:00
|
|
|
TypeExactOut,
|
2022-06-28 16:03:50 -07:00
|
|
|
relayerFee
|
|
|
|
);
|
2022-01-20 08:52:35 -08:00
|
|
|
|
2022-06-30 14:49:49 -07:00
|
|
|
// approve token bridge to spend feeTokens
|
2022-01-21 10:37:14 -08:00
|
|
|
TransferHelper.safeApprove(
|
2022-06-30 14:49:49 -07:00
|
|
|
FEE_TOKEN_ADDRESS,
|
|
|
|
TOKEN_BRIDGE_ADDRESS,
|
2022-01-21 10:37:14 -08:00
|
|
|
swapParams.amountOut
|
|
|
|
);
|
2022-01-20 08:52:35 -08:00
|
|
|
|
|
|
|
// send transfer with payload to the TokenBridge
|
2022-06-30 14:49:49 -07:00
|
|
|
TokenBridge(TOKEN_BRIDGE_ADDRESS).transferTokensWithPayload(
|
|
|
|
FEE_TOKEN_ADDRESS,
|
2022-01-21 10:37:14 -08:00
|
|
|
swapParams.amountOut,
|
|
|
|
targetChainId,
|
|
|
|
targetContractAddress,
|
|
|
|
nonce,
|
|
|
|
payload
|
2022-01-20 08:52:35 -08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-01-22 11:25:01 -08:00
|
|
|
// necessary for receiving native assets
|
2022-01-20 08:52:35 -08:00
|
|
|
receive() external payable {}
|
2022-01-11 08:29:49 -08:00
|
|
|
}
|