From 705d70f2648905b30b2966f435480f1d842fa5b3 Mon Sep 17 00:00:00 2001 From: Drew Date: Tue, 28 Jun 2022 23:03:50 +0000 Subject: [PATCH 1/8] Integrate new payload 3 update --- contracts/contracts/CrossChainSwapV2.sol | 610 ++++------------- contracts/contracts/CrossChainSwapV3.sol | 626 ++++-------------- contracts/contracts/SwapHelper.sol | 14 +- .../tokenImplementations/WormUSD.sol | 11 + .../migrations/tokens/1_initial_migration.js | 5 + .../migrations/tokens/2_deploy_contracts.js | 7 + 6 files changed, 290 insertions(+), 983 deletions(-) create mode 100644 contracts/contracts/tokenImplementations/WormUSD.sol create mode 100644 contracts/migrations/tokens/1_initial_migration.js create mode 100644 contracts/migrations/tokens/2_deploy_contracts.js diff --git a/contracts/contracts/CrossChainSwapV2.sol b/contracts/contracts/CrossChainSwapV2.sol index 3689efa..63a96e6 100644 --- a/contracts/contracts/CrossChainSwapV2.sol +++ b/contracts/contracts/CrossChainSwapV2.sol @@ -18,13 +18,11 @@ interface TokenBridge { uint256 amount, uint16 recipientChain, bytes32 recipient, - uint256 arbiterFee, uint32 nonce, bytes memory payload ) external payable returns (uint64); function completeTransferWithPayload( - bytes memory encodedVm, - address feeRecipient + bytes memory encodedVm ) external returns (bytes memory); } @@ -45,8 +43,6 @@ contract CrossChainSwapV2 { uint8 public immutable typeExactOut = 2; uint8 public immutable typeNativeSwap = 1; uint8 public immutable typeTokenSwap = 2; - uint16 public immutable expectedVaaLength = 274; - uint8 public immutable terraChainId = 3; IUniswapV2Router02 public immutable swapRouter; address public immutable feeTokenAddress; address public immutable tokenBridgeAddress; @@ -78,19 +74,12 @@ contract CrossChainSwapV2 { function _getParsedPayload( bytes calldata encodedVaa, uint8 swapFunctionType, - uint8 swapCurrencyType, - address feeRecipient + uint8 swapCurrencyType ) private returns (SwapHelper.DecodedVaaParameters memory payload) { // complete the transfer on the token bridge bytes memory vmPayload = TokenBridge( tokenBridgeAddress - ).completeTransferWithPayload(encodedVaa, feeRecipient); - - // make sure payload is the right size - require( - vmPayload.length==expectedVaaLength, - "VAA has the wrong number of bytes" - ); + ).completeTransferWithPayload(encodedVaa); // parse the payload payload = SwapHelper.decodeVaaPayload(vmPayload); @@ -110,32 +99,14 @@ contract CrossChainSwapV2 { function recvAndSwapExactNativeIn( bytes calldata encodedVaa ) external payable returns (uint256[] memory amounts) { - // check token balance before redeeming the payload - (,bytes memory queriedBalanceBefore) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); - // redeem and fetch parsed payload SwapHelper.DecodedVaaParameters memory payload = _getParsedPayload( encodedVaa, typeExactIn, - typeNativeSwap, - msg.sender // feeRecipient + typeNativeSwap ); - // query token balance after redeeming the payload - (,bytes memory queriedBalanceAfter) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); - - // the balance change is the swap amount (less relayer fees) - uint256 swapAmountLessFees = balanceAfter - balanceBefore; - // create dynamic address array // uniswap won't take fixed size array address[] memory uniPath = new address[](2); @@ -152,6 +123,12 @@ contract CrossChainSwapV2 { "tokenOut must be wrapped native asset" ); + // pay relayer before attempting to do the swap + // reflect payment in second swap amount + IERC20 feeToken = IERC20(feeTokenAddress); + feeToken.safeTransfer(msg.sender, payload.relayerFee); + uint256 swapAmountLessFees = payload.swapAmount - payload.relayerFee; + // approve the router to spend tokens TransferHelper.safeApprove( uniPath[0], @@ -200,289 +177,18 @@ contract CrossChainSwapV2 { } } - /// @dev Executes exactIn token swap and pays the relayer - function recvAndSwapExactIn( - bytes calldata encodedVaa - ) external returns (uint256[] memory amounts) { - // check token balance before redeeming the payload - (,bytes memory queriedBalanceBefore) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); - - // redeem and fetch the parsed payload - SwapHelper.DecodedVaaParameters memory payload = - _getParsedPayload( - encodedVaa, - typeExactIn, - typeTokenSwap, - msg.sender // feeRecipient - ); - - // query token balance after redeeming the payload - (,bytes memory queriedBalanceAfter) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); - - // the balance change is the swap amount (less relayer fees) - uint256 swapAmountLessFees = balanceAfter - balanceBefore; - - // 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]; - - // make sure first element in path is UST - require(uniPath[0]==feeTokenAddress, "tokenIn must be UST"); - - // approve the router to spend tokens - TransferHelper.safeApprove( - uniPath[0], - address(swapRouter), - swapAmountLessFees - ); - - // try to perform the swap - try swapRouter.swapExactTokensForTokens( - swapAmountLessFees, - payload.estimatedAmount, - uniPath, - payload.recipientAddress, - payload.deadline - ) returns (uint256[] memory amounts) { - // used in UI to tell user they're getting - // their desired token - emit SwapResult( - payload.recipientAddress, - uniPath[1], - msg.sender, - amounts[1], - 1 - ); - return amounts; - } catch { - // swap failed - return UST to recipient - IERC20(feeTokenAddress).safeTransfer( - payload.recipientAddress, - swapAmountLessFees - ); - - // used in UI to tell user they're getting - // UST instead of their desired token - emit SwapResult( - payload.recipientAddress, - uniPath[0], - msg.sender, - swapAmountLessFees, - 0 - ); - } - } - - /// @dev Executes exactIn native asset and token swaps before - /// sending a custom payload to the TokenBridge - function _swapExactInBeforeTransfer( - uint256 amountIn, - uint256 amountOutMinimum, - address contractCaller, - address[] calldata path, - uint256 deadline - ) internal returns (uint256 amountOut) { - // approve the router to spend tokens - TransferHelper.safeApprove( - path[0], - address(swapRouter), - amountIn - ); - - // perform the swap - uint256[] memory amounts = swapRouter.swapExactTokensForTokens( - amountIn, - amountOutMinimum, - path, - address(this), - deadline - ); - amountOut = amounts[1]; - } - - /// @dev Calls _swapExactInBeforeTransfer and encodes custom payload with - /// instructions for executing token swaps on the destination chain - function swapExactInAndTransfer( - SwapHelper.ExactInParameters calldata swapParams, - address[] calldata path, - uint256 relayerFee, - uint16 targetChainId, - bytes32 targetContractAddress, - uint32 nonce - ) external { - require( - swapParams.amountOutMinimum > relayerFee, - "insufficient amountOutMinimum to pay relayer" - ); - require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" - ); - - // send tokens to this contract - IERC20 token = IERC20(path[0]); - token.safeTransferFrom(msg.sender, address(this), swapParams.amountIn); - - // peform the first swap - uint256 amountOut = _swapExactInBeforeTransfer( - swapParams.amountIn, - swapParams.amountOutMinimum, - msg.sender, - path[0:2], - swapParams.deadline - ); - - // encode payload for second swap - bytes memory payload = abi.encodePacked( - swapParams.targetAmountOutMinimum, - swapParams.targetChainRecipient, - path[2], - path[3], - swapParams.deadline, - swapParams.poolFee, - typeExactIn, - typeTokenSwap - ); - - // approve token bridge to spend feeTokens (UST) - TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, - amountOut - ); - - // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, - amountOut, - targetChainId, - targetContractAddress, - relayerFee, - nonce, - payload - ); - } - - /// @dev Calls _swapExactInBeforeTransfer and encodes custom payload with - /// instructions for executing native asset swaps on the destination chain - function swapExactNativeInAndTransfer( - SwapHelper.ExactInParameters calldata swapParams, - address[] calldata path, - uint256 relayerFee, - uint16 targetChainId, - bytes32 targetContractAddress, - uint32 nonce - ) external payable { - require( - swapParams.amountOutMinimum > relayerFee, - "insufficient amountOutMinimum to pay relayer" - ); - require( - path[0]==wrappedNative, - "tokenIn must be wrapped native asset for first swap" - ); - require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" - ); - require(msg.value > 0, "must pass non 0 native asset amount"); - - // wrap native asset - IWETH(wrappedNative).deposit{ - value : msg.value - }(); - - // peform the first swap - uint256 amountOut = _swapExactInBeforeTransfer( - msg.value, - swapParams.amountOutMinimum, - msg.sender, - path[0:2], - swapParams.deadline - ); - - // create payload variable - bytes memory payload; - - // UST is native to Terra - no need for swap instructions - if (targetChainId == terraChainId) { - payload = abi.encodePacked( - swapParams.targetChainRecipient - ); - } else { - payload = abi.encodePacked( - swapParams.targetAmountOutMinimum, - swapParams.targetChainRecipient, - path[2], - path[3], - swapParams.deadline, - swapParams.poolFee, - typeExactIn, - typeNativeSwap - ); - } - - // approve token bridge to spend feeTokens (UST) - TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, - amountOut - ); - - // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, - amountOut, - targetChainId, - targetContractAddress, - relayerFee, - nonce, - payload - ); - } - /// @dev Executes exactOut native asset swap and pays the relayer function recvAndSwapExactNativeOut( bytes calldata encodedVaa ) external returns (uint256 amountInUsed) { - // check token balance before redeeming the payload - (,bytes memory queriedBalanceBefore) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); - // redeem and fetch parsed payload SwapHelper.DecodedVaaParameters memory payload = _getParsedPayload( encodedVaa, typeExactOut, - typeNativeSwap, - msg.sender // feeRecipient + typeNativeSwap ); - // query token balance after redeeming the payload - (,bytes memory queriedBalanceAfter) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); - - // the balance change is the swap amount (less relayer fees) - uint256 maxAmountInLessFees = balanceAfter - balanceBefore; - - // amountOut is the estimated swap amount for exact out methods - uint256 amountOut = payload.estimatedAmount; - // create dynamic address array - uniswap won't take fixed size array address[] memory uniPath = new address[](2); uniPath[0] = payload.path[0]; @@ -497,7 +203,16 @@ contract CrossChainSwapV2 { payload.path[1]==wrappedNative, "tokenOut must be wrapped native asset" ); - + + // pay relayer before attempting to do the swap + // reflect payment in second swap amount + IERC20 feeToken = IERC20(feeTokenAddress); + 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; + // approve the router to spend tokens TransferHelper.safeApprove( uniPath[0], @@ -562,105 +277,103 @@ contract CrossChainSwapV2 { } } - /// @dev Executes exactOut token swap and pays the relayer - function recvAndSwapExactOut( - bytes calldata encodedVaa - ) external returns (uint256 amountInUsed) { - // check token balance before redeeming the payload - (,bytes memory queriedBalanceBefore) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); - // redeem and fetch parsed payload - SwapHelper.DecodedVaaParameters memory payload = - _getParsedPayload( - encodedVaa, - typeExactOut, - typeTokenSwap, - msg.sender // feeRecipient - ); - - // query token balance after redeeming the payload - (,bytes memory queriedBalanceAfter) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); - - // the balance change is the swap amount (less relayer fees) - uint256 maxAmountInLessFees = balanceAfter - balanceBefore; - - // amountOut is the estimated swap amount for exact out methods - uint256 amountOut = payload.estimatedAmount; - - // 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]; - require(uniPath[0]==feeTokenAddress, "tokenIn must be UST"); - + /// @dev Executes exactIn native asset and token swaps before + /// sending a custom payload to the TokenBridge + function _swapExactInBeforeTransfer( + uint256 amountIn, + uint256 amountOutMinimum, + address contractCaller, + address[] calldata path, + uint256 deadline + ) internal returns (uint256 amountOut) { // approve the router to spend tokens TransferHelper.safeApprove( - uniPath[0], + path[0], address(swapRouter), - maxAmountInLessFees - ); + amountIn + ); - // try to perform the swap - try swapRouter.swapTokensForExactTokens( - amountOut, - maxAmountInLessFees, - uniPath, - payload.recipientAddress, - payload.deadline - ) returns (uint256[] memory amounts) { - // amountIn used is first element in array - amountInUsed = amounts[0]; - - // refund recipient with any UST not used in the swap - if (amountInUsed < maxAmountInLessFees) { - TransferHelper.safeApprove( - feeTokenAddress, - address(swapRouter), - 0 - ); - IERC20(feeTokenAddress).safeTransfer( - payload.recipientAddress, - maxAmountInLessFees - amountInUsed - ); - } - - // used in UI to tell user they're getting - // their desired token - emit SwapResult( - payload.recipientAddress, - uniPath[1], - msg.sender, - amounts[1], - 1 - ); - return amountInUsed; - } catch { - // swap failed - return UST to recipient - IERC20(feeTokenAddress).safeTransfer( - payload.recipientAddress, - maxAmountInLessFees - ); - - // used in UI to tell user they're getting - // UST instead of their desired token - emit SwapResult( - payload.recipientAddress, - uniPath[0], - msg.sender, - maxAmountInLessFees, - 0 - ); - } + // perform the swap + uint256[] memory amounts = swapRouter.swapExactTokensForTokens( + amountIn, + amountOutMinimum, + path, + address(this), + deadline + ); + amountOut = amounts[1]; } + /// @dev Calls _swapExactInBeforeTransfer and encodes custom payload with + /// instructions for executing native asset swaps on the destination chain + function swapExactNativeInAndTransfer( + SwapHelper.ExactInParameters calldata swapParams, + address[] calldata path, + uint256 relayerFee, + uint16 targetChainId, + bytes32 targetContractAddress, + uint32 nonce + ) external payable { + require( + swapParams.amountOutMinimum > relayerFee, + "insufficient amountOutMinimum to pay relayer" + ); + require( + path[0]==wrappedNative, + "tokenIn must be wrapped native asset for first swap" + ); + require( + path[1]==feeTokenAddress, + "tokenOut must be UST for first swap" + ); + require(msg.value > 0, "must pass non 0 native asset amount"); + + // wrap native asset + IWETH(wrappedNative).deposit{ + value : msg.value + }(); + + // peform the first swap + uint256 amountOut = _swapExactInBeforeTransfer( + msg.value, + swapParams.amountOutMinimum, + msg.sender, + path[0:2], + swapParams.deadline + ); + + // create payload with target swap instructions + bytes memory payload = abi.encodePacked( + swapParams.targetAmountOutMinimum, + swapParams.targetChainRecipient, + path[2], + path[3], + swapParams.deadline, + swapParams.poolFee, + typeExactIn, + typeNativeSwap, + relayerFee + ); + + // approve token bridge to spend feeTokens (UST) + TransferHelper.safeApprove( + feeTokenAddress, + tokenBridgeAddress, + amountOut + ); + + // send transfer with payload to the TokenBridge + TokenBridge(tokenBridgeAddress).transferTokensWithPayload( + feeTokenAddress, + amountOut, + targetChainId, + targetContractAddress, + nonce, + payload + ); + } + /// @dev Executes exactOut native asset and token swaps before /// sending a custom payload to the TokenBridge function _swapExactOutBeforeTransfer( @@ -712,74 +425,6 @@ contract CrossChainSwapV2 { } } - /// @dev Calls _swapExactOutBeforeTransfer and encodes custom payload with - /// instructions for executing token swaps on the destination chain - function swapExactOutAndTransfer( - SwapHelper.ExactOutParameters calldata swapParams, - address[] calldata path, - uint256 relayerFee, - uint16 targetChainId, - bytes32 targetContractAddress, - uint32 nonce - ) external { - require( - swapParams.amountOut > relayerFee, - "insufficient amountOut to pay relayer" - ); - require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" - ); - - // send tokens to this contract before swap - IERC20 token = IERC20(path[0]); - token.safeTransferFrom( - msg.sender, - address(this), - swapParams.amountInMaximum - ); - - // peform the first swap - _swapExactOutBeforeTransfer( - swapParams.amountOut, - swapParams.amountInMaximum, - msg.sender, - path[0:2], - swapParams.deadline, - typeTokenSwap - ); - - // encode payload for second swap - bytes memory payload = abi.encodePacked( - swapParams.targetAmountOut, - swapParams.targetChainRecipient, - path[2], - path[3], - swapParams.deadline, - swapParams.poolFee, - typeExactOut, - typeTokenSwap - ); - - // approve token bridge to spend feeTokens (UST) - TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, - swapParams.amountOut - ); - - // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, - swapParams.amountOut, - targetChainId, - targetContractAddress, - relayerFee, - nonce, - payload - ); - } - /// @dev Calls _swapExactOutBeforeTransfer and encodes custom payload with /// instructions for executing native asset swaps on the destination chain function swapExactNativeOutAndTransfer( @@ -819,26 +464,18 @@ contract CrossChainSwapV2 { typeNativeSwap ); - // create payload variable - bytes memory payload; - - // UST is native to Terra - no need for swap instructions - if (targetChainId == terraChainId) { - payload = abi.encodePacked( - swapParams.targetChainRecipient - ); - } else { - payload = abi.encodePacked( - swapParams.targetAmountOut, - swapParams.targetChainRecipient, - path[2], - path[3], - swapParams.deadline, - swapParams.poolFee, - typeExactOut, - typeNativeSwap - ); - } + // create payload with target swap instructions + bytes memory payload = abi.encodePacked( + swapParams.targetAmountOut, + swapParams.targetChainRecipient, + path[2], + path[3], + swapParams.deadline, + swapParams.poolFee, + typeExactOut, + typeNativeSwap, + relayerFee + ); // approve token bridge to spend feeTokens (UST) TransferHelper.safeApprove( @@ -853,7 +490,6 @@ contract CrossChainSwapV2 { swapParams.amountOut, targetChainId, targetContractAddress, - relayerFee, nonce, payload ); diff --git a/contracts/contracts/CrossChainSwapV3.sol b/contracts/contracts/CrossChainSwapV3.sol index 5ca0368..2212c2b 100644 --- a/contracts/contracts/CrossChainSwapV3.sol +++ b/contracts/contracts/CrossChainSwapV3.sol @@ -18,13 +18,11 @@ interface TokenBridge { uint256 amount, uint16 recipientChain, bytes32 recipient, - uint256 arbiterFee, uint32 nonce, bytes memory payload ) external payable returns (uint64); function completeTransferWithPayload( - bytes memory encodedVm, - address feeRecipient + bytes memory encodedVm ) external returns (bytes memory); } @@ -49,8 +47,6 @@ contract CrossChainSwapV3 { uint8 public immutable typeExactOut = 2; uint8 public immutable typeNativeSwap = 1; uint8 public immutable typeTokenSwap = 2; - uint16 public immutable expectedVaaLength = 274; - uint8 public immutable terraChainId = 3; IUniswapRouter public immutable swapRouter; address public immutable feeTokenAddress; address public immutable tokenBridgeAddress; @@ -78,23 +74,16 @@ contract CrossChainSwapV3 { ); /// @dev Returns the parsed TokenBridge payload which contains swap - /// instructions after redeeming from the VAA from the TokenBridge + /// instructions after redeeming the VAA from the TokenBridge function _getParsedPayload( bytes calldata encodedVaa, uint8 swapFunctionType, - uint8 swapCurrencyType, - address feeRecipient + uint8 swapCurrencyType ) private returns (SwapHelper.DecodedVaaParameters memory payload) { // complete the transfer on the token bridge bytes memory vmPayload = TokenBridge( tokenBridgeAddress - ).completeTransferWithPayload(encodedVaa, feeRecipient); - - // make sure payload is the right size - require( - vmPayload.length==expectedVaaLength, - "VAA has the wrong number of bytes" - ); + ).completeTransferWithPayload(encodedVaa); // parse the payload payload = SwapHelper.decodeVaaPayload(vmPayload); @@ -108,36 +97,19 @@ contract CrossChainSwapV3 { payload.swapCurrencyType==swapCurrencyType, "incorrect swapCurrencyType in payload" ); - } + } /// @dev Executes exactIn native asset swap and pays the relayer function recvAndSwapExactNativeIn( bytes calldata encodedVaa ) external returns (uint256 amountOut) { - // check token balance before redeeming the payload - (,bytes memory queriedBalanceBefore) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); - + // redeem and fetch parsed payload SwapHelper.DecodedVaaParameters memory payload = _getParsedPayload( encodedVaa, typeExactIn, - typeNativeSwap, - msg.sender // feeRecipient - ); - - // query token balance after redeeming the payload - (,bytes memory queriedBalanceAfter) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); - - // the balance change is the swap amount (less relayer fees) - uint256 swapAmountLessFees = balanceAfter - balanceBefore; + typeNativeSwap + ); // sanity check path require( @@ -149,6 +121,12 @@ contract CrossChainSwapV3 { "tokenOut must be wrapped Native" ); + // pay relayer before attempting to do the swap + // reflect payment in second swap amount + IERC20 feeToken = IERC20(feeTokenAddress); + feeToken.safeTransfer(msg.sender, payload.relayerFee); + uint256 swapAmountLessFees = payload.swapAmount - payload.relayerFee; + // approve the router to spend tokens TransferHelper.safeApprove( payload.path[0], @@ -204,301 +182,18 @@ contract CrossChainSwapV3 { } } - /// @dev Executes exactIn token swap and pays the relayer - function recvAndSwapExactIn( - bytes calldata encodedVaa - ) external returns (uint256 amountOut) { - // check token balance before redeeming the payload - (,bytes memory queriedBalanceBefore) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); - - // redeem and fetch the parsed payload - SwapHelper.DecodedVaaParameters memory payload = - _getParsedPayload( - encodedVaa, - typeExactIn, - typeTokenSwap, - msg.sender // feeRecipient - ); - - // query token balance after redeeming the payload - (,bytes memory queriedBalanceAfter) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); - - // the balance change is the swap amount (less relayer fees) - uint256 swapAmountLessFees = balanceAfter - balanceBefore; - - // check path to see if first element is the feeToken - require(payload.path[0]==feeTokenAddress, "tokenIn must be UST"); - - // approve the router to spend tokens - TransferHelper.safeApprove( - payload.path[0], - address(swapRouter), - swapAmountLessFees - ); - - // set swap options with user params - ISwapRouter.ExactInputSingleParams memory params = - ISwapRouter.ExactInputSingleParams({ - tokenIn: payload.path[0], - tokenOut: payload.path[1], - fee: payload.poolFee, - recipient: payload.recipientAddress, - deadline: payload.deadline, - amountIn: swapAmountLessFees, - amountOutMinimum: payload.estimatedAmount, - sqrtPriceLimitX96: 0 - }); - - // try to perform the swap - try swapRouter.exactInputSingle(params) returns (uint256 amountOut) { - // used in UI to tell user they're getting - // their desired token - emit SwapResult( - payload.recipientAddress, - payload.path[1], - msg.sender, - amountOut, - 1 - ); - return amountOut; - } catch { - // swap failed - return UST to recipient - IERC20(feeTokenAddress).safeTransfer( - payload.recipientAddress, - swapAmountLessFees - ); - - // used in UI to tell user they're getting - // UST instead of their desired token - emit SwapResult( - payload.recipientAddress, - payload.path[0], - msg.sender, - swapAmountLessFees, - 0 - ); - } - } - - /// @dev Executes exactIn native asset and token swaps before - /// sending a custom payload to the TokenBridge - function _swapExactInBeforeTransfer( - uint256 amountIn, - uint256 amountOutMinimum, - address contractCaller, - address[] calldata path, - uint256 deadline, - uint24 poolFee, - uint8 swapType - ) internal returns (uint256 amountOut) { - if (swapType == typeTokenSwap) { - // transfer the allowed amount of tokens to this contract - IERC20 token = IERC20(path[0]); - token.safeTransferFrom(contractCaller, address(this), amountIn); - - // approve the router to spend tokens - TransferHelper.safeApprove( - path[0], - address(swapRouter), - amountIn - ); - } - - // set swap options with user params - ISwapRouter.ExactInputSingleParams memory params = - ISwapRouter.ExactInputSingleParams({ - tokenIn: path[0], - tokenOut: path[1], - fee: poolFee, - recipient: address(this), - deadline: deadline, - amountIn: amountIn, - amountOutMinimum: amountOutMinimum, - sqrtPriceLimitX96: 0 - }); - - // perform the swap - if (swapType == typeTokenSwap) { - amountOut = swapRouter.exactInputSingle(params); - } else { // native swap - amountOut = swapRouter.exactInputSingle{value: amountIn}(params); - } - } - - /// @dev Calls _swapExactInBeforeTransfer and encodes custom payload with - /// instructions for executing token swaps on the destination chain - function swapExactInAndTransfer( - SwapHelper.ExactInParameters calldata swapParams, - address[] calldata path, - uint256 relayerFee, - uint16 targetChainId, - bytes32 targetContractAddress, - uint32 nonce - ) external { - require( - swapParams.amountOutMinimum > relayerFee, - "insufficient amountOutMinimum to pay relayer" - ); - require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" - ); - - // peform the first swap - uint256 amountOut = _swapExactInBeforeTransfer( - swapParams.amountIn, - swapParams.amountOutMinimum, - msg.sender, - path[0:2], - swapParams.deadline, - swapParams.poolFee, - typeTokenSwap - ); - - // encode payload for second swap - bytes memory payload = abi.encodePacked( - swapParams.targetAmountOutMinimum, - swapParams.targetChainRecipient, - path[2], - path[3], - swapParams.deadline, - swapParams.poolFee, - typeExactIn, - typeTokenSwap - ); - - // approve token bridge to spend feeTokens (UST) - TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, - amountOut - ); - - // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, - amountOut, - targetChainId, - targetContractAddress, - relayerFee, - nonce, - payload - ); - } - - /// @dev Calls _swapExactInBeforeTransfer and encodes custom payload with - /// instructions for executing native asset swaps on the destination chain - function swapExactNativeInAndTransfer( - SwapHelper.ExactInParameters calldata swapParams, - address[] calldata path, - uint256 relayerFee, - uint16 targetChainId, - bytes32 targetContractAddress, - uint32 nonce - ) external payable { - require( - swapParams.amountOutMinimum > relayerFee, - "insufficient amountOutMinimum to pay relayer" - ); - require( - path[0]==wrappedNative, - "tokenIn must be wrapped native asset for first swap" - ); - require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" - ); - require(msg.value > 0, "must pass non 0 native asset amount"); - - // peform the first swap - uint256 amountOut = _swapExactInBeforeTransfer( - msg.value, - swapParams.amountOutMinimum, - msg.sender, - path[0:2], - swapParams.deadline, - swapParams.poolFee, - typeNativeSwap - ); - - // create payload variable - bytes memory payload; - - // UST is native to Terra - no need for swap instructions - if (targetChainId == terraChainId) { - payload = abi.encodePacked( - swapParams.targetChainRecipient - ); - } else { - payload = abi.encodePacked( - swapParams.targetAmountOutMinimum, - swapParams.targetChainRecipient, - path[2], - path[3], - swapParams.deadline, - swapParams.poolFee, - typeExactIn, - typeNativeSwap - ); - } - - // approve token bridge to spend feeTokens (UST) - TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, - amountOut - ); - - // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, - amountOut, - targetChainId, - targetContractAddress, - relayerFee, - nonce, - payload - ); - } - /// @dev Executes exactOut native asset swap and pays the relayer function recvAndSwapExactNativeOut( bytes calldata encodedVaa ) external returns (uint256 amountInUsed) { - // check token balance before redeeming the payload - (,bytes memory queriedBalanceBefore) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); - // redeem and fetch parsed payload SwapHelper.DecodedVaaParameters memory payload = _getParsedPayload( encodedVaa, typeExactOut, - typeNativeSwap, - msg.sender // feeRecipient + typeNativeSwap ); - // query token balance after redeeming the payload - (,bytes memory queriedBalanceAfter) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); - - // the balance change is the swap amount (less relayer fees) - uint256 maxAmountInLessFees = balanceAfter - balanceBefore; - // sanity check path require( payload.path[0]==feeTokenAddress, @@ -509,6 +204,12 @@ contract CrossChainSwapV3 { "tokenOut must be wrapped native asset" ); + // pay relayer before attempting to do the swap + // reflect payment in second swap amount + IERC20 feeToken = IERC20(feeTokenAddress); + 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; @@ -580,106 +281,117 @@ contract CrossChainSwapV3 { } } - /// @dev Executes exactOut token swap and pays the relayer - function recvAndSwapExactOut( - bytes calldata encodedVaa - ) external returns (uint256 amountInUsed) { - // check token balance before redeeming the payload - (,bytes memory queriedBalanceBefore) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256)); + /// @dev Executes exactIn native asset and token swaps before + /// sending a custom payload to the TokenBridge + function _swapExactInBeforeTransfer( + uint256 amountIn, + uint256 amountOutMinimum, + address contractCaller, + address[] calldata path, + uint256 deadline, + uint24 poolFee, + uint8 swapType + ) internal returns (uint256 amountOut) { + if (swapType == typeTokenSwap) { + // transfer the allowed amount of tokens to this contract + IERC20 token = IERC20(path[0]); + token.safeTransferFrom(contractCaller, address(this), amountIn); - // redeem and fetch parsed payload - SwapHelper.DecodedVaaParameters memory payload = - _getParsedPayload( - encodedVaa, - typeExactOut, - typeTokenSwap, - msg.sender // feeRecipient + // approve the router to spend tokens + TransferHelper.safeApprove( + path[0], + address(swapRouter), + amountIn ); - - // query token balance after redeeming the payload - (,bytes memory queriedBalanceAfter) = feeTokenAddress.staticcall( - abi.encodeWithSelector(IERC20.balanceOf.selector, - address(this) - )); - uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256)); - - // the balance change is the swap amount (less relayer fees) - uint256 maxAmountInLessFees = balanceAfter - balanceBefore; - - // check path to see if first element is the feeToken - require(payload.path[0]==feeTokenAddress, "tokenIn must be UST"); - - // amountOut is the estimated swap amount for exact out methods - uint256 amountOut = payload.estimatedAmount; - - // approve the router to spend tokens - TransferHelper.safeApprove( - payload.path[0], - address(swapRouter), - maxAmountInLessFees - ); + } // set swap options with user params - ISwapRouter.ExactOutputSingleParams memory params = - ISwapRouter.ExactOutputSingleParams({ - tokenIn: payload.path[0], - tokenOut: payload.path[1], - fee: payload.poolFee, - recipient: payload.recipientAddress, - deadline: payload.deadline, - amountOut: amountOut, - amountInMaximum: maxAmountInLessFees, + ISwapRouter.ExactInputSingleParams memory params = + ISwapRouter.ExactInputSingleParams({ + tokenIn: path[0], + tokenOut: path[1], + fee: poolFee, + recipient: address(this), + deadline: deadline, + amountIn: amountIn, + amountOutMinimum: amountOutMinimum, sqrtPriceLimitX96: 0 }); - // try to perform the swap - try swapRouter.exactOutputSingle(params) returns (uint256 amountInUsed) { - // refund recipient with any UST not used in the swap - if (amountInUsed < maxAmountInLessFees) { - TransferHelper.safeApprove( - feeTokenAddress, - address(swapRouter), - 0 - ); - IERC20(feeTokenAddress).safeTransfer( - payload.recipientAddress, - maxAmountInLessFees - amountInUsed - ); - } - - // used in UI to tell user they're getting - // their desired token - emit SwapResult( - payload.recipientAddress, - payload.path[1], - msg.sender, - amountOut, - 1 - ); - return amountInUsed; - } catch { - // swap failed - return UST to recipient - IERC20(feeTokenAddress).safeTransfer( - payload.recipientAddress, - maxAmountInLessFees - ); - - // used in UI to tell user they're getting - // UST instead of their desired token - emit SwapResult( - payload.recipientAddress, - payload.path[0], - msg.sender, - maxAmountInLessFees, - 0 - ); + // perform the swap + if (swapType == typeTokenSwap) { + amountOut = swapRouter.exactInputSingle(params); + } else { // native swap + amountOut = swapRouter.exactInputSingle{value: amountIn}(params); } } + /// @dev Calls _swapExactInBeforeTransfer and encodes custom payload with + /// instructions for executing native asset swaps on the destination chain + function swapExactNativeInAndTransfer( + SwapHelper.ExactInParameters calldata swapParams, + address[] calldata path, + uint256 relayerFee, + uint16 targetChainId, + bytes32 targetContractAddress, + uint32 nonce + ) external payable { + require( + swapParams.amountOutMinimum > relayerFee, + "insufficient amountOutMinimum to pay relayer" + ); + require( + path[0]==wrappedNative, + "tokenIn must be wrapped native asset for first swap" + ); + require( + path[1]==feeTokenAddress, + "tokenOut must be UST for first swap" + ); + require(msg.value > 0, "must pass non 0 native asset amount"); + + // peform the first swap + uint256 amountOut = _swapExactInBeforeTransfer( + msg.value, + swapParams.amountOutMinimum, + msg.sender, + path[0:2], + swapParams.deadline, + swapParams.poolFee, + typeNativeSwap + ); + + // create payload with target swap instructions + bytes memory payload = abi.encodePacked( + swapParams.targetAmountOutMinimum, + swapParams.targetChainRecipient, + path[2], + path[3], + swapParams.deadline, + swapParams.poolFee, + typeExactIn, + typeNativeSwap, + relayerFee + ); + + // approve token bridge to spend feeTokens (UST) + TransferHelper.safeApprove( + feeTokenAddress, + tokenBridgeAddress, + amountOut + ); + + // send transfer with payload to the TokenBridge + TokenBridge(tokenBridgeAddress).transferTokensWithPayload( + feeTokenAddress, + amountOut, + targetChainId, + targetContractAddress, + nonce, + payload + ); + } + /// @dev Executes exactOut native asset and token swaps before /// sending a custom payload to the TokenBridge function _swapExactOutBeforeTransfer( @@ -751,67 +463,6 @@ contract CrossChainSwapV3 { } } - /// @dev Calls _swapExactOutBeforeTransfer and encodes custom payload with - /// instructions for executing token swaps on the destination chain - function swapExactOutAndTransfer( - SwapHelper.ExactOutParameters calldata swapParams, - address[] calldata path, - uint256 relayerFee, - uint16 targetChainId, - bytes32 targetContractAddress, - uint32 nonce - ) external { - require( - swapParams.amountOut > relayerFee, - "insufficient amountOut to pay relayer" - ); - require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" - ); - - // peform the first swap - _swapExactOutBeforeTransfer( - swapParams.amountOut, - swapParams.amountInMaximum, - msg.sender, - path[0:2], - swapParams.deadline, - swapParams.poolFee, - typeTokenSwap - ); - - // encode payload for second swap - bytes memory payload = abi.encodePacked( - swapParams.targetAmountOut, - swapParams.targetChainRecipient, - path[2], - path[3], - swapParams.deadline, - swapParams.poolFee, - typeExactOut, - typeTokenSwap - ); - - // approve token bridge to spend feeTokens (UST) - TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, - swapParams.amountOut - ); - - // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, - swapParams.amountOut, - targetChainId, - targetContractAddress, - relayerFee, - nonce, - payload - ); - } - /// @dev Calls _swapExactOutBeforeTransfer and encodes custom payload with /// instructions for executing native asset swaps on the destination chain function swapExactNativeOutAndTransfer( @@ -847,26 +498,18 @@ contract CrossChainSwapV3 { typeNativeSwap ); - // create payload variable - bytes memory payload; - - // UST is native to Terra - no need for swap instructions - if (targetChainId == terraChainId) { - payload = abi.encodePacked( - swapParams.targetChainRecipient - ); - } else { - payload = abi.encodePacked( - swapParams.targetAmountOut, - swapParams.targetChainRecipient, - path[2], - path[3], - swapParams.deadline, - swapParams.poolFee, - typeExactOut, - typeNativeSwap - ); - } + // create payload with target swap instructions + bytes memory payload = abi.encodePacked( + swapParams.targetAmountOut, + swapParams.targetChainRecipient, + path[2], + path[3], + swapParams.deadline, + swapParams.poolFee, + typeExactOut, + typeNativeSwap, + relayerFee + ); // approve token bridge to spend feeTokens (UST) TransferHelper.safeApprove( @@ -881,7 +524,6 @@ contract CrossChainSwapV3 { swapParams.amountOut, targetChainId, targetContractAddress, - relayerFee, nonce, payload ); diff --git a/contracts/contracts/SwapHelper.sol b/contracts/contracts/SwapHelper.sol index 4b41f72..c97ace3 100644 --- a/contracts/contracts/SwapHelper.sol +++ b/contracts/contracts/SwapHelper.sol @@ -6,12 +6,11 @@ pragma abicoder v2; import './IWormhole.sol'; import 'solidity-bytes-utils/contracts/BytesLib.sol'; - /// @title Helper library for cross-chain swaps /// @notice Contains functions necessary for parsing encoded VAAs /// and structs containing swap parameters library SwapHelper { - using BytesLib for bytes; + using BytesLib for bytes; /// @dev Parameters needed for exactIn swap type struct ExactInParameters { @@ -40,7 +39,7 @@ library SwapHelper { uint8 version; uint256 swapAmount; address contractAddress; - uint256 relayerFee; + bytes32 fromAddress; uint256 estimatedAmount; address recipientAddress; address[2] path; @@ -48,6 +47,7 @@ library SwapHelper { uint24 poolFee; uint8 swapFunctionType; uint8 swapCurrencyType; + uint256 relayerFee; } /// @dev Decodes parameters encoded in a VAA @@ -71,7 +71,7 @@ library SwapHelper { // skip index += 2; - decoded.relayerFee = vmPayload.toUint256(index); + decoded.fromAddress = vmPayload.toBytes32(index); index += 32; decoded.estimatedAmount = vmPayload.toUint256(index); @@ -99,5 +99,11 @@ library SwapHelper { index += 1; decoded.swapCurrencyType = vmPayload.toUint8(index); + index += 1; + + decoded.relayerFee = vmPayload.toUint256(index); + index += 32; + + require(vmPayload.length == index, "invalid payload length"); } } \ No newline at end of file diff --git a/contracts/contracts/tokenImplementations/WormUSD.sol b/contracts/contracts/tokenImplementations/WormUSD.sol new file mode 100644 index 0000000..5d89b40 --- /dev/null +++ b/contracts/contracts/tokenImplementations/WormUSD.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.7.6; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract WormUSD is ERC20 { + constructor(address mintToAddress) ERC20("wormUSD", "WUSD"){ + _mint(mintToAddress, 1000000000*10**18); + } +} \ No newline at end of file diff --git a/contracts/migrations/tokens/1_initial_migration.js b/contracts/migrations/tokens/1_initial_migration.js new file mode 100644 index 0000000..16a7ba5 --- /dev/null +++ b/contracts/migrations/tokens/1_initial_migration.js @@ -0,0 +1,5 @@ +const Migrations = artifacts.require("Migrations"); + +module.exports = function (deployer) { + deployer.deploy(Migrations); +}; diff --git a/contracts/migrations/tokens/2_deploy_contracts.js b/contracts/migrations/tokens/2_deploy_contracts.js new file mode 100644 index 0000000..87048a7 --- /dev/null +++ b/contracts/migrations/tokens/2_deploy_contracts.js @@ -0,0 +1,7 @@ +const WormUSD = artifacts.require("WormUSD"); + +module.exports = async function (deployer, network) { + const mintAddress = "0x3278E0aE2bc9EC8754b67928e0F5ff8f99CE5934"; + + await deployer.deploy(WormUSD, mintAddress); +}; From ae69dd1bc8c125c1bcc08ef75007bcaab2a76c98 Mon Sep 17 00:00:00 2001 From: Drew Date: Tue, 28 Jun 2022 23:10:11 +0000 Subject: [PATCH 2/8] Add mintToAddress from .env --- contracts/migrations/tokens/2_deploy_contracts.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/migrations/tokens/2_deploy_contracts.js b/contracts/migrations/tokens/2_deploy_contracts.js index 87048a7..e3bc8d4 100644 --- a/contracts/migrations/tokens/2_deploy_contracts.js +++ b/contracts/migrations/tokens/2_deploy_contracts.js @@ -1,7 +1,9 @@ +require("dotenv").config({ path: ".env" }); +i; const WormUSD = artifacts.require("WormUSD"); module.exports = async function (deployer, network) { - const mintAddress = "0x3278E0aE2bc9EC8754b67928e0F5ff8f99CE5934"; + const mintAddress = process.env.mintToAddress; await deployer.deploy(WormUSD, mintAddress); }; From da2fc8b4c6371ffe6e8c1a9c159b96954cce4b5b Mon Sep 17 00:00:00 2001 From: Drew Date: Wed, 29 Jun 2022 15:17:27 +0000 Subject: [PATCH 3/8] Update token decimals for test token --- contracts/contracts/tokenImplementations/WormUSD.sol | 5 +++-- contracts/deploy_token.sh | 4 ++++ contracts/migrations/tokens/2_deploy_contracts.js | 6 ++++-- 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100755 contracts/deploy_token.sh diff --git a/contracts/contracts/tokenImplementations/WormUSD.sol b/contracts/contracts/tokenImplementations/WormUSD.sol index 5d89b40..d382f91 100644 --- a/contracts/contracts/tokenImplementations/WormUSD.sol +++ b/contracts/contracts/tokenImplementations/WormUSD.sol @@ -5,7 +5,8 @@ pragma solidity ^0.7.6; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract WormUSD is ERC20 { - constructor(address mintToAddress) ERC20("wormUSD", "WUSD"){ - _mint(mintToAddress, 1000000000*10**18); + constructor(address mintToAddress, uint8 decimals, uint256 supply) ERC20("wormUSD", "WUSD"){ + _setupDecimals(decimals); + _mint(mintToAddress, supply*10**decimals); } } \ No newline at end of file diff --git a/contracts/deploy_token.sh b/contracts/deploy_token.sh new file mode 100755 index 0000000..d542515 --- /dev/null +++ b/contracts/deploy_token.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -euo pipefail + +npx truffle migrate --config cfg/truffle-config.tokens.js --network goerli --reset diff --git a/contracts/migrations/tokens/2_deploy_contracts.js b/contracts/migrations/tokens/2_deploy_contracts.js index e3bc8d4..bce3241 100644 --- a/contracts/migrations/tokens/2_deploy_contracts.js +++ b/contracts/migrations/tokens/2_deploy_contracts.js @@ -1,9 +1,11 @@ require("dotenv").config({ path: ".env" }); -i; + const WormUSD = artifacts.require("WormUSD"); module.exports = async function (deployer, network) { const mintAddress = process.env.mintToAddress; + const tokenDecimals = process.env.decimals; + const tokenSupply = process.env.supply; - await deployer.deploy(WormUSD, mintAddress); + await deployer.deploy(WormUSD, mintAddress, tokenDecimals, tokenSupply); }; From 1630b18b477f3e2e63ee179a776ff1434bcde2d6 Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 30 Jun 2022 19:45:37 +0000 Subject: [PATCH 4/8] Change polygon cfg --- contracts/cfg/truffle-config.polygon.js | 66 ++++++++++++------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/contracts/cfg/truffle-config.polygon.js b/contracts/cfg/truffle-config.polygon.js index d34342e..c1a12a9 100644 --- a/contracts/cfg/truffle-config.polygon.js +++ b/contracts/cfg/truffle-config.polygon.js @@ -1,7 +1,6 @@ -const HDWalletProvider = require('@truffle/hdwallet-provider'); +const HDWalletProvider = require("@truffle/hdwallet-provider"); - -require('dotenv').config({path:'.env'}); +require("dotenv").config({ path: ".env" }); /** * Use this file to configure your truffle project. It's seeded with some @@ -29,9 +28,9 @@ require('dotenv').config({path:'.env'}); // const mnemonic = fs.readFileSync('.secret').toString().trim(); module.exports = { - contracts_directory: './contracts', - contracts_build_directory: './build/contracts', - migrations_directory: './migrations/polygon', + contracts_directory: "./contracts", + contracts_build_directory: "./build/contracts", + migrations_directory: "./migrations/polygon", /** * Networks define how you connect to your ethereum client and let you set the * defaults web3 uses to send transactions. If you don't specify one truffle @@ -42,18 +41,18 @@ module.exports = { * $ truffle test --network */ - networks: { + networks: { // Useful for testing. The `development` name is special - truffle uses it by default // if it's defined here and no other network is specified at the command line. // You should run a client (like ganache-cli, geth or parity) in a separate terminal // tab if you use this network and you must also set the `host`, `port` and `network_id` // options below to some value. // - development: { - host: '127.0.0.1', // Localhost (default: none) - port: 8545, // Standard Ethereum port (default: none) - network_id: '*', // Any network (default: none) - }, + development: { + host: "127.0.0.1", // Localhost (default: none) + port: 8545, // Standard Ethereum port (default: none) + network_id: "*", // Any network (default: none) + }, // Another network with more advanced options... // advanced: { // port: 8777, // Custom port @@ -65,14 +64,15 @@ module.exports = { // }, // Useful for deploying to a public network. // NB: It's important to wrap the provider as a function. - mumbai: { - provider: () => new HDWalletProvider(process.env.ETH_PRIVATE_KEY, process.env.MUMBAI_PROVIDER), - network_id: 80001, - //gas: 4465030, - //confirmations: 2, // # of confs to wait between deployments. (default: 0) - //timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) - //skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) - }, + mumbai: { + provider: () => new HDWalletProvider(process.env.ETH_PRIVATE_KEY, process.env.MUMBAI_PROVIDER), + network_id: 80001, + gasPrice: 80000000000, + gas: 7000000, + //confirmations: 2, // # of confs to wait between deployments. (default: 0) + timeoutBlocks: 50, // # of blocks before a deployment times out (minimum/default: 50) + skipDryRun: true, // Skip dry run before migrations? (default: false for public nets ) + }, // Useful for private networks // private: { // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), @@ -89,16 +89,16 @@ module.exports = { // Configure your compilers compilers: { solc: { - version: '0.7.6', // Fetch exact version from solc-bin (default: truffle's version) + version: "0.7.6", // Fetch exact version from solc-bin (default: truffle's version) // docker: true, // Use '0.5.1' you've installed locally with docker (default: false) // settings: { // See the solidity docs for advice about optimization and evmVersion optimizer: { - enabled: false, - runs: 200 + enabled: false, + runs: 200, }, // evmVersion: 'byzantium' // } - } + }, }, // Truffle DB is currently disabled by default; to enable it, change enabled: @@ -108,17 +108,17 @@ module.exports = { // NOTE: It is not possible to migrate your contracts to truffle DB and you should // make a backup of your artifacts to a safe location before enabling this feature. // - // After you backed up your artifacts you can utilize db by running migrate as follows: + // After you backed up your artifacts you can utilize db by running migrate as follows: // $ truffle migrate --reset --compile-all // // db: { - // enabled: false, - // host: '127.0.0.1', - // adapter: { - // name: 'sqlite', - // settings: { - // directory: '.db' - // } - // } + // enabled: false, + // host: '127.0.0.1', + // adapter: { + // name: 'sqlite', + // settings: { + // directory: '.db' + // } + // } // } }; From 1debacee60c6f5f6b5ab3e83723edfddcb466477 Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 30 Jun 2022 19:51:00 +0000 Subject: [PATCH 5/8] Update feeToken address in deployment scripts --- .../avalanche/2_deploy_contracts.js | 36 ++++++++----------- .../migrations/bsc/2_deploy_contracts.js | 36 ++++++++----------- .../migrations/ethereum/2_deploy_contracts.js | 10 ++---- .../migrations/polygon/2_deploy_contracts.js | 10 ++---- 4 files changed, 34 insertions(+), 58 deletions(-) diff --git a/contracts/migrations/avalanche/2_deploy_contracts.js b/contracts/migrations/avalanche/2_deploy_contracts.js index 09d6a26..4a1bbf9 100644 --- a/contracts/migrations/avalanche/2_deploy_contracts.js +++ b/contracts/migrations/avalanche/2_deploy_contracts.js @@ -5,29 +5,23 @@ const SwapHelper = artifacts.require("SwapHelper"); const scriptsAddressPath = "../react/src/addresses"; -module.exports = async function(deployer, network) { - const routerAddress = "0x7e3411b04766089cfaa52db688855356a12f05d1"; // hurricaneswap - const feeTokenAddress = "0xe09ed38e5cd1014444846f62376ac88c5232cde9"; // wUST - const tokenBridgeAddress = "0x61E44E506Ca5659E6c0bba9b678586fA2d729756"; - const wrappedAvaxAddress = "0x1d308089a2d1ced3f1ce36b1fcaf815b07217be3"; +module.exports = async function (deployer, network) { + const routerAddress = "0x7e3411b04766089cfaa52db688855356a12f05d1"; // hurricaneswap router + const feeTokenAddress = "0x8F23C5BE43FBfE7a30c04e4eDEE3D18995Fe7E2d"; // wormUSD + const tokenBridgeAddress = "0x61E44E506Ca5659E6c0bba9b678586fA2d729756"; + const wrappedAvaxAddress = "0x1d308089a2d1ced3f1ce36b1fcaf815b07217be3"; - await deployer.deploy(SwapHelper); - await deployer.link(SwapHelper, CrossChainSwapV2); - await deployer.deploy( - CrossChainSwapV2, - routerAddress, - feeTokenAddress, - tokenBridgeAddress, - wrappedAvaxAddress - ); - - // save the contract address somewhere - await fsp.mkdir(scriptsAddressPath, { recursive: true }); + await deployer.deploy(SwapHelper); + await deployer.link(SwapHelper, CrossChainSwapV2); + await deployer.deploy(CrossChainSwapV2, routerAddress, feeTokenAddress, tokenBridgeAddress, wrappedAvaxAddress); - await fsp.writeFile( - `${scriptsAddressPath}/${network}.ts`, - `export const SWAP_CONTRACT_ADDRESS = '${CrossChainSwapV2.address}';` - ); + // save the contract address somewhere + await fsp.mkdir(scriptsAddressPath, { recursive: true }); + + await fsp.writeFile( + `${scriptsAddressPath}/${network}.ts`, + `export const SWAP_CONTRACT_ADDRESS = '${CrossChainSwapV2.address}';` + ); //deployer.link(ConvertLib, MetaCoin); //deployer.deploy(MetaCoin); diff --git a/contracts/migrations/bsc/2_deploy_contracts.js b/contracts/migrations/bsc/2_deploy_contracts.js index 5219f85..d2b570f 100644 --- a/contracts/migrations/bsc/2_deploy_contracts.js +++ b/contracts/migrations/bsc/2_deploy_contracts.js @@ -5,29 +5,23 @@ const SwapHelper = artifacts.require("SwapHelper"); const scriptsAddressPath = "../react/src/addresses"; -module.exports = async function(deployer, network) { - const routerAddress = "0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3"; // pancakeswap - const feeTokenAddress = "0x7b8eae1e85c8b189ee653d3f78733f4f788bb2c1"; // wUST - const tokenBridgeAddress = "0x9dcF9D205C9De35334D646BeE44b2D2859712A09"; - const wrappedBnbAddress = "0xae13d989dac2f0debff460ac112a837c89baa7cd"; +module.exports = async function (deployer, network) { + const routerAddress = "0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3"; // pancakeswap + const feeTokenAddress = "0x2A29D46D7e0B997358E9726DA0210Af212f2dfd7"; // wormUSD + const tokenBridgeAddress = "0x9dcF9D205C9De35334D646BeE44b2D2859712A09"; + const wrappedBnbAddress = "0xae13d989dac2f0debff460ac112a837c89baa7cd"; - await deployer.deploy(SwapHelper); - await deployer.link(SwapHelper, CrossChainSwapV2); - await deployer.deploy( - CrossChainSwapV2, - routerAddress, - feeTokenAddress, - tokenBridgeAddress, - wrappedBnbAddress - ); - - // save the contract address somewhere - await fsp.mkdir(scriptsAddressPath, { recursive: true }); + await deployer.deploy(SwapHelper); + await deployer.link(SwapHelper, CrossChainSwapV2); + await deployer.deploy(CrossChainSwapV2, routerAddress, feeTokenAddress, tokenBridgeAddress, wrappedBnbAddress); - await fsp.writeFile( - `${scriptsAddressPath}/${network}.ts`, - `export const SWAP_CONTRACT_ADDRESS = '${CrossChainSwapV2.address}';` - ); + // save the contract address somewhere + await fsp.mkdir(scriptsAddressPath, { recursive: true }); + + await fsp.writeFile( + `${scriptsAddressPath}/${network}.ts`, + `export const SWAP_CONTRACT_ADDRESS = '${CrossChainSwapV2.address}';` + ); //deployer.link(ConvertLib, MetaCoin); //deployer.deploy(MetaCoin); diff --git a/contracts/migrations/ethereum/2_deploy_contracts.js b/contracts/migrations/ethereum/2_deploy_contracts.js index 251a0b3..86d9d73 100644 --- a/contracts/migrations/ethereum/2_deploy_contracts.js +++ b/contracts/migrations/ethereum/2_deploy_contracts.js @@ -7,19 +7,13 @@ const scriptsAddressPath = "../react/src/addresses"; module.exports = async function (deployer, network) { const routerAddress = "0xE592427A0AEce92De3Edee1F18E0157C05861564"; - const feeTokenAddress = "0x36Ed51Afc79619b299b238898E72ce482600568a"; // wUST + const feeTokenAddress = "0x6336c2dA64408Fcc277e0E1104aC6c34c431464c"; // wormUSD const tokenBridgeAddress = "0xF890982f9310df57d00f659cf4fd87e65adEd8d7"; const wrappedEthAddress = "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6"; await deployer.deploy(SwapHelper); await deployer.link(SwapHelper, CrossChainSwapV3); - await deployer.deploy( - CrossChainSwapV3, - routerAddress, - feeTokenAddress, - tokenBridgeAddress, - wrappedEthAddress - ); + await deployer.deploy(CrossChainSwapV3, routerAddress, feeTokenAddress, tokenBridgeAddress, wrappedEthAddress); // save the contract address somewhere await fsp.mkdir(scriptsAddressPath, { recursive: true }); diff --git a/contracts/migrations/polygon/2_deploy_contracts.js b/contracts/migrations/polygon/2_deploy_contracts.js index 563b13a..9aa0792 100644 --- a/contracts/migrations/polygon/2_deploy_contracts.js +++ b/contracts/migrations/polygon/2_deploy_contracts.js @@ -7,19 +7,13 @@ const scriptsAddressPath = "../react/src/addresses"; module.exports = async function (deployer, network) { const routerAddress = "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff"; // quickwap - const feeTokenAddress = "0xe3a1c77e952b57b5883f6c906fc706fcc7d4392c"; // wUST + const feeTokenAddress = "0xcf7BEE494B42cB5A902dF000158037Ad334eB4a7"; // wormUSD const tokenBridgeAddress = "0x377D55a7928c046E18eEbb61977e714d2a76472a"; const wrappedMaticAddress = "0x9c3c9283d3e44854697cd22d3faa240cfb032889"; await deployer.deploy(SwapHelper); await deployer.link(SwapHelper, CrossChainSwapV2); - await deployer.deploy( - CrossChainSwapV2, - routerAddress, - feeTokenAddress, - tokenBridgeAddress, - wrappedMaticAddress - ); + await deployer.deploy(CrossChainSwapV2, routerAddress, feeTokenAddress, tokenBridgeAddress, wrappedMaticAddress); // save the contract address somewhere await fsp.mkdir(scriptsAddressPath, { recursive: true }); From 330122eeceb31e16b9a048b1441da0c19d55f549 Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 30 Jun 2022 21:49:49 +0000 Subject: [PATCH 6/8] Refactor contracts --- contracts/cfg/truffle-config.tokens.js | 123 +++++++++ contracts/contracts/CrossChainSwapV2.sol | 199 ++++++-------- contracts/contracts/CrossChainSwapV3.sol | 242 ++++++------------ .../contracts/{ => shared}/IWormhole.sol | 0 contracts/contracts/{ => shared}/Structs.sol | 0 .../contracts/{ => shared}/SwapHelper.sol | 4 - contracts/contracts/shared/TokenBridge.sol | 18 ++ contracts/contracts/shared/WETH.sol | 11 + 8 files changed, 309 insertions(+), 288 deletions(-) create mode 100644 contracts/cfg/truffle-config.tokens.js rename contracts/contracts/{ => shared}/IWormhole.sol (100%) rename contracts/contracts/{ => shared}/Structs.sol (100%) rename contracts/contracts/{ => shared}/SwapHelper.sol (95%) create mode 100644 contracts/contracts/shared/TokenBridge.sol create mode 100644 contracts/contracts/shared/WETH.sol diff --git a/contracts/cfg/truffle-config.tokens.js b/contracts/cfg/truffle-config.tokens.js new file mode 100644 index 0000000..3add8dc --- /dev/null +++ b/contracts/cfg/truffle-config.tokens.js @@ -0,0 +1,123 @@ +const HDWalletProvider = require("@truffle/hdwallet-provider"); + +require("dotenv").config({ path: ".env" }); + +/** + * Use this file to configure your truffle project. It's seeded with some + * common settings for different networks and features like migrations, + * compilation and testing. Uncomment the ones you need or modify + * them to suit your project as necessary. + * + * More information about configuration can be found at: + * + * trufflesuite.com/docs/advanced/configuration + * + * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider) + * to sign your transactions before they're sent to a remote public node. Infura accounts + * are available for free at: infura.io/register. + * + * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate + * public/private key pairs. If you're publishing your code to GitHub make sure you load this + * phrase from a file you've .gitignored so it doesn't accidentally become public. + * + */ + +// const HDWalletProvider = require('@truffle/hdwallet-provider'); +// +// const fs = require('fs'); +// const mnemonic = fs.readFileSync('.secret').toString().trim(); + +module.exports = { + contracts_directory: "./contracts", + contracts_build_directory: "./build/contracts", + migrations_directory: "./migrations/tokens", + /** + * Networks define how you connect to your ethereum client and let you set the + * defaults web3 uses to send transactions. If you don't specify one truffle + * will spin up a development blockchain for you on port 9545 when you + * run `develop` or `test`. You can ask a truffle command to use a specific + * network from the command line, e.g + * + * $ truffle test --network + */ + + networks: { + // Useful for testing. The `development` name is special - truffle uses it by default + // if it's defined here and no other network is specified at the command line. + // You should run a client (like ganache-cli, geth or parity) in a separate terminal + // tab if you use this network and you must also set the `host`, `port` and `network_id` + // options below to some value. + // + development: { + host: "127.0.0.1", // Localhost (default: none) + port: 8545, // Standard Ethereum port (default: none) + network_id: "*", // Any network (default: none) + }, + // Another network with more advanced options... + // advanced: { + // port: 8777, // Custom port + // network_id: 1342, // Custom network + // gas: 8500000, // Gas sent with each transaction (default: ~6700000) + // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) + // from:
, // Account to send txs from (default: accounts[0]) + // websocket: true // Enable EventEmitter interface for web3 (default: false) + // }, + // Useful for deploying to a public network. + // NB: It's important to wrap the provider as a function. + goerli: { + provider: () => new HDWalletProvider(process.env.ETH_PRIVATE_KEY, process.env.GOERLI_PROVIDER), + network_id: 5, + //gas: 4465030, + //confirmations: 2, // # of confs to wait between deployments. (default: 0) + //timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) + //skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) + }, + // Useful for private networks + // private: { + // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), + // network_id: 2111, // This network is yours, in the cloud. + // production: true // Treats this network as if it was a public net. (default: false) + // } + }, + + // Set default mocha options here, use special reporters etc. + mocha: { + // timeout: 100000 + }, + + // Configure your compilers + compilers: { + solc: { + version: "0.7.6", // Fetch exact version from solc-bin (default: truffle's version) + // docker: true, // Use '0.5.1' you've installed locally with docker (default: false) + // settings: { // See the solidity docs for advice about optimization and evmVersion + optimizer: { + enabled: false, + runs: 200, + }, + // evmVersion: 'byzantium' + // } + }, + }, + + // Truffle DB is currently disabled by default; to enable it, change enabled: + // false to enabled: true. The default storage location can also be + // overridden by specifying the adapter settings, as shown in the commented code below. + // + // NOTE: It is not possible to migrate your contracts to truffle DB and you should + // make a backup of your artifacts to a safe location before enabling this feature. + // + // After you backed up your artifacts you can utilize db by running migrate as follows: + // $ truffle migrate --reset --compile-all + // + // db: { + // enabled: false, + // host: '127.0.0.1', + // adapter: { + // name: 'sqlite', + // settings: { + // directory: '.db' + // } + // } + // } +}; diff --git a/contracts/contracts/CrossChainSwapV2.sol b/contracts/contracts/CrossChainSwapV2.sol index 63a96e6..4e25c32 100644 --- a/contracts/contracts/CrossChainSwapV2.sol +++ b/contracts/contracts/CrossChainSwapV2.sol @@ -3,8 +3,10 @@ pragma solidity ^0.7.6; pragma abicoder v2; -import './IWormhole.sol'; -import './SwapHelper.sol'; +import './shared/IWormhole.sol'; +import './shared/SwapHelper.sol'; +import './shared/TokenBridge.sol'; +import './shared/WETH.sol'; import 'solidity-bytes-utils/contracts/BytesLib.sol'; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts/token/ERC20/SafeERC20.sol'; @@ -12,41 +14,18 @@ import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol'; import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; -interface TokenBridge { - function transferTokensWithPayload( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint32 nonce, - bytes memory payload - ) external payable returns (uint64); - function completeTransferWithPayload( - bytes memory encodedVm - ) external returns (bytes memory); -} - - -interface IWETH is IERC20 { - function deposit() external payable; - function withdraw(uint amount) external; -} - - /// @title A cross-chain UniswapV2 example /// @notice Swaps against UniswapV2 pools and uses Wormhole TokenBridge /// for cross-chain transfers contract CrossChainSwapV2 { using SafeERC20 for IERC20; using BytesLib for bytes; - uint8 public immutable typeExactIn = 1; - uint8 public immutable typeExactOut = 2; - uint8 public immutable typeNativeSwap = 1; - uint8 public immutable typeTokenSwap = 2; - IUniswapV2Router02 public immutable swapRouter; - address public immutable feeTokenAddress; - address public immutable tokenBridgeAddress; - address public immutable wrappedNative; + 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; constructor( address _swapRouterAddress, @@ -54,10 +33,10 @@ contract CrossChainSwapV2 { address _tokenBridgeAddress, address _wrappedNativeAddress ) { - swapRouter = IUniswapV2Router02(_swapRouterAddress); - feeTokenAddress = _feeTokenAddress; - tokenBridgeAddress = _tokenBridgeAddress; - wrappedNative = _wrappedNativeAddress; + SWAP_ROUTER = IUniswapV2Router02(_swapRouterAddress); + FEE_TOKEN_ADDRESS = _feeTokenAddress; + TOKEN_BRIDGE_ADDRESS = _tokenBridgeAddress; + WRAPPED_NATIVE = _wrappedNativeAddress; } /// @dev Used to communicate information about executed swaps to UI/user @@ -73,12 +52,11 @@ contract CrossChainSwapV2 { /// instructions after redeeming the VAA from the TokenBridge function _getParsedPayload( bytes calldata encodedVaa, - uint8 swapFunctionType, - uint8 swapCurrencyType + uint8 swapFunctionType ) private returns (SwapHelper.DecodedVaaParameters memory payload) { // complete the transfer on the token bridge bytes memory vmPayload = TokenBridge( - tokenBridgeAddress + TOKEN_BRIDGE_ADDRESS ).completeTransferWithPayload(encodedVaa); // parse the payload @@ -89,10 +67,6 @@ contract CrossChainSwapV2 { payload.swapFunctionType==swapFunctionType, "incorrect swapFunctionType in payload" ); - require( - payload.swapCurrencyType==swapCurrencyType, - "incorrect swapCurrencyType in payload" - ); } /// @dev Executes exactIn native asset swap and pays the relayer @@ -103,8 +77,7 @@ contract CrossChainSwapV2 { SwapHelper.DecodedVaaParameters memory payload = _getParsedPayload( encodedVaa, - typeExactIn, - typeNativeSwap + TypeExactIn ); // create dynamic address array @@ -115,29 +88,29 @@ contract CrossChainSwapV2 { // sanity check path require( - uniPath[0]==feeTokenAddress, - "tokenIn must be UST" + uniPath[0]==FEE_TOKEN_ADDRESS, + "tokenIn must be feeToken" ); require( - uniPath[1]==wrappedNative, + uniPath[1]==WRAPPED_NATIVE, "tokenOut must be wrapped native asset" ); // pay relayer before attempting to do the swap // reflect payment in second swap amount - IERC20 feeToken = IERC20(feeTokenAddress); + IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); feeToken.safeTransfer(msg.sender, payload.relayerFee); uint256 swapAmountLessFees = payload.swapAmount - payload.relayerFee; // approve the router to spend tokens TransferHelper.safeApprove( uniPath[0], - address(swapRouter), + address(SWAP_ROUTER), swapAmountLessFees ); // try to execute the swap - try swapRouter.swapExactTokensForTokens( + try SWAP_ROUTER.swapExactTokensForTokens( swapAmountLessFees, payload.estimatedAmount, uniPath, @@ -145,7 +118,7 @@ contract CrossChainSwapV2 { payload.deadline ) returns (uint256[] memory amounts) { // unwrap native and send to recipient - IWETH(wrappedNative).withdraw(amounts[1]); + IWETH(WRAPPED_NATIVE).withdraw(amounts[1]); payable(payload.recipientAddress).transfer(amounts[1]); // used in UI to tell user they're getting @@ -159,14 +132,14 @@ contract CrossChainSwapV2 { ); return amounts; } catch { - // swap failed - return UST to recipient - IERC20(feeTokenAddress).safeTransfer( + // swap failed - return feeToken to recipient + IERC20(FEE_TOKEN_ADDRESS).safeTransfer( payload.recipientAddress, swapAmountLessFees ); // used in UI to tell user they're getting - // UST instead of their desired native asset + // feeToken instead of their desired native asset emit SwapResult( payload.recipientAddress, uniPath[0], @@ -185,8 +158,7 @@ contract CrossChainSwapV2 { SwapHelper.DecodedVaaParameters memory payload = _getParsedPayload( encodedVaa, - typeExactOut, - typeNativeSwap + TypeExactOut ); // create dynamic address array - uniswap won't take fixed size array @@ -196,17 +168,17 @@ contract CrossChainSwapV2 { // sanity check path require( - uniPath[0]==feeTokenAddress, - "tokenIn must be UST" + uniPath[0]==FEE_TOKEN_ADDRESS, + "tokenIn must be feeToken" ); require( - payload.path[1]==wrappedNative, + payload.path[1]==WRAPPED_NATIVE, "tokenOut must be wrapped native asset" ); // pay relayer before attempting to do the swap // reflect payment in second swap amount - IERC20 feeToken = IERC20(feeTokenAddress); + IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); feeToken.safeTransfer(msg.sender, payload.relayerFee); uint256 maxAmountInLessFees = payload.swapAmount - payload.relayerFee; @@ -216,12 +188,12 @@ contract CrossChainSwapV2 { // approve the router to spend tokens TransferHelper.safeApprove( uniPath[0], - address(swapRouter), + address(SWAP_ROUTER), maxAmountInLessFees ); // try to perform the swap - try swapRouter.swapTokensForExactTokens( + try SWAP_ROUTER.swapTokensForExactTokens( amountOut, maxAmountInLessFees, uniPath, @@ -231,21 +203,21 @@ contract CrossChainSwapV2 { // amountIn used is first element in array amountInUsed = amounts[0]; - // refund recipient with any UST not used in the swap + // refund recipient with any feeToken not used in the swap if (amountInUsed < maxAmountInLessFees) { TransferHelper.safeApprove( - feeTokenAddress, - address(swapRouter), + FEE_TOKEN_ADDRESS, + address(SWAP_ROUTER), 0 ); - IERC20(feeTokenAddress).safeTransfer( + IERC20(FEE_TOKEN_ADDRESS).safeTransfer( payload.recipientAddress, maxAmountInLessFees - amountInUsed ); } // unwrap native and send to recipient - IWETH(wrappedNative).withdraw(amounts[1]); + IWETH(WRAPPED_NATIVE).withdraw(amounts[1]); payable(payload.recipientAddress).transfer(amounts[1]); // used in UI to tell user they're getting @@ -259,14 +231,14 @@ contract CrossChainSwapV2 { ); return amountInUsed; } catch { - // swap failed - return UST to recipient - IERC20(feeTokenAddress).safeTransfer( + // swap failed - return feeToken to recipient + IERC20(FEE_TOKEN_ADDRESS).safeTransfer( payload.recipientAddress, maxAmountInLessFees ); // used in UI to tell user they're getting - // UST instead of their desired native asset + // feeToken instead of their desired native asset emit SwapResult( payload.recipientAddress, uniPath[0], @@ -278,8 +250,7 @@ contract CrossChainSwapV2 { } - /// @dev Executes exactIn native asset and token swaps before - /// sending a custom payload to the TokenBridge + /// @dev Executes exactIn native asset swap function _swapExactInBeforeTransfer( uint256 amountIn, uint256 amountOutMinimum, @@ -290,12 +261,12 @@ contract CrossChainSwapV2 { // approve the router to spend tokens TransferHelper.safeApprove( path[0], - address(swapRouter), + address(SWAP_ROUTER), amountIn ); // perform the swap - uint256[] memory amounts = swapRouter.swapExactTokensForTokens( + uint256[] memory amounts = SWAP_ROUTER.swapExactTokensForTokens( amountIn, amountOutMinimum, path, @@ -320,17 +291,17 @@ contract CrossChainSwapV2 { "insufficient amountOutMinimum to pay relayer" ); require( - path[0]==wrappedNative, + path[0]==WRAPPED_NATIVE, "tokenIn must be wrapped native asset for first swap" ); require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" + path[1]==FEE_TOKEN_ADDRESS, + "tokenOut must be feeToken for first swap" ); require(msg.value > 0, "must pass non 0 native asset amount"); // wrap native asset - IWETH(wrappedNative).deposit{ + IWETH(WRAPPED_NATIVE).deposit{ value : msg.value }(); @@ -351,21 +322,20 @@ contract CrossChainSwapV2 { path[3], swapParams.deadline, swapParams.poolFee, - typeExactIn, - typeNativeSwap, + TypeExactIn, relayerFee ); - // approve token bridge to spend feeTokens (UST) + // approve token bridge to spend feeTokens TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, + FEE_TOKEN_ADDRESS, + TOKEN_BRIDGE_ADDRESS, amountOut ); // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, + TokenBridge(TOKEN_BRIDGE_ADDRESS).transferTokensWithPayload( + FEE_TOKEN_ADDRESS, amountOut, targetChainId, targetContractAddress, @@ -374,25 +344,23 @@ contract CrossChainSwapV2 { ); } - /// @dev Executes exactOut native asset and token swaps before - /// sending a custom payload to the TokenBridge + /// @dev Executes exactOut native asset swaps function _swapExactOutBeforeTransfer( uint256 amountOut, uint256 amountInMaximum, address contractCaller, address[] calldata path, - uint256 deadline, - uint8 swapType + uint256 deadline ) internal { // approve the router to spend tokens TransferHelper.safeApprove( path[0], - address(swapRouter), + address(SWAP_ROUTER), amountInMaximum ); // perform the swap - uint256[] memory amounts = swapRouter.swapTokensForExactTokens( + uint256[] memory amounts = SWAP_ROUTER.swapTokensForExactTokens( amountOut, amountInMaximum, path, @@ -405,23 +373,14 @@ contract CrossChainSwapV2 { // refund contractCaller with any amountIn that wasn't spent if (amountInUsed < amountInMaximum) { - TransferHelper.safeApprove(path[0], address(swapRouter), 0); - if (swapType == typeTokenSwap) { - // send remaining tokens to contractCaller - IERC20 token = IERC20(path[0]); - token.safeTransfer( - contractCaller, - amountInMaximum - amountInUsed - ); - } else { - // unwrap remaining native asset and send to contractCaller - IWETH(wrappedNative).withdraw( - amountInMaximum - amountInUsed - ); - payable(contractCaller).transfer( - amountInMaximum - amountInUsed - ); - } + // 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 + ); } } @@ -440,17 +399,17 @@ contract CrossChainSwapV2 { "insufficient amountOut to pay relayer" ); require( - path[0]==wrappedNative, + path[0]==WRAPPED_NATIVE, "tokenIn must be wrapped native asset for first swap" ); require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" + path[1]==FEE_TOKEN_ADDRESS, + "tokenOut must be feeToken for first swap" ); require(msg.value > 0, "must pass non 0 native asset amount"); // wrap native asset - IWETH(wrappedNative).deposit{ + IWETH(WRAPPED_NATIVE).deposit{ value : msg.value }(); @@ -460,8 +419,7 @@ contract CrossChainSwapV2 { msg.value, msg.sender, path[0:2], - swapParams.deadline, - typeNativeSwap + swapParams.deadline ); // create payload with target swap instructions @@ -472,21 +430,20 @@ contract CrossChainSwapV2 { path[3], swapParams.deadline, swapParams.poolFee, - typeExactOut, - typeNativeSwap, + TypeExactOut, relayerFee ); - // approve token bridge to spend feeTokens (UST) + // approve token bridge to spend feeTokens TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, + FEE_TOKEN_ADDRESS, + TOKEN_BRIDGE_ADDRESS, swapParams.amountOut ); // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, + TokenBridge(TOKEN_BRIDGE_ADDRESS).transferTokensWithPayload( + FEE_TOKEN_ADDRESS, swapParams.amountOut, targetChainId, targetContractAddress, diff --git a/contracts/contracts/CrossChainSwapV3.sol b/contracts/contracts/CrossChainSwapV3.sol index 2212c2b..aa9421a 100644 --- a/contracts/contracts/CrossChainSwapV3.sol +++ b/contracts/contracts/CrossChainSwapV3.sol @@ -3,8 +3,10 @@ pragma solidity ^0.7.6; pragma abicoder v2; -import './IWormhole.sol'; -import './SwapHelper.sol'; +import './shared/IWormhole.sol'; +import './shared/SwapHelper.sol'; +import './shared/TokenBridge.sol'; +import './shared/WETH.sol'; import 'solidity-bytes-utils/contracts/BytesLib.sol'; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts/token/ERC20/SafeERC20.sol'; @@ -12,26 +14,6 @@ import '@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol'; import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol'; -interface TokenBridge { - function transferTokensWithPayload( - address token, - uint256 amount, - uint16 recipientChain, - bytes32 recipient, - uint32 nonce, - bytes memory payload - ) external payable returns (uint64); - function completeTransferWithPayload( - bytes memory encodedVm - ) external returns (bytes memory); -} - - -interface IWETH is IERC20 { - function withdraw(uint amount) external; -} - - interface IUniswapRouter is ISwapRouter { function refundETH() external payable; } @@ -43,14 +25,12 @@ interface IUniswapRouter is ISwapRouter { contract CrossChainSwapV3 { using SafeERC20 for IERC20; using BytesLib for bytes; - uint8 public immutable typeExactIn = 1; - uint8 public immutable typeExactOut = 2; - uint8 public immutable typeNativeSwap = 1; - uint8 public immutable typeTokenSwap = 2; - IUniswapRouter public immutable swapRouter; - address public immutable feeTokenAddress; - address public immutable tokenBridgeAddress; - address public immutable wrappedNative; + uint8 public immutable TypeExactIn = 1; + uint8 public immutable TypeExactOut = 2; + IUniswapRouter public immutable SWAP_ROUTER; + address public immutable FEE_TOKEN_ADDRESS; + address public immutable TOKEN_BRIDGE_ADDRESS; + address public immutable WRAPPED_NATIVE; constructor( address _swapRouterAddress, @@ -58,10 +38,10 @@ contract CrossChainSwapV3 { address _tokenBridgeAddress, address _wrappedNativeAddress ) { - swapRouter = IUniswapRouter(_swapRouterAddress); - feeTokenAddress = _feeTokenAddress; - tokenBridgeAddress = _tokenBridgeAddress; - wrappedNative = _wrappedNativeAddress; + SWAP_ROUTER = IUniswapRouter(_swapRouterAddress); + FEE_TOKEN_ADDRESS = _feeTokenAddress; + TOKEN_BRIDGE_ADDRESS = _tokenBridgeAddress; + WRAPPED_NATIVE = _wrappedNativeAddress; } /// @dev Used to communicate information about executed swaps to UI/user @@ -77,12 +57,11 @@ contract CrossChainSwapV3 { /// instructions after redeeming the VAA from the TokenBridge function _getParsedPayload( bytes calldata encodedVaa, - uint8 swapFunctionType, - uint8 swapCurrencyType + uint8 swapFunctionType ) private returns (SwapHelper.DecodedVaaParameters memory payload) { // complete the transfer on the token bridge bytes memory vmPayload = TokenBridge( - tokenBridgeAddress + TOKEN_BRIDGE_ADDRESS ).completeTransferWithPayload(encodedVaa); // parse the payload @@ -93,10 +72,6 @@ contract CrossChainSwapV3 { payload.swapFunctionType==swapFunctionType, "incorrect swapFunctionType in payload" ); - require( - payload.swapCurrencyType==swapCurrencyType, - "incorrect swapCurrencyType in payload" - ); } /// @dev Executes exactIn native asset swap and pays the relayer @@ -107,30 +82,29 @@ contract CrossChainSwapV3 { SwapHelper.DecodedVaaParameters memory payload = _getParsedPayload( encodedVaa, - typeExactIn, - typeNativeSwap + TypeExactIn ); // sanity check path require( - payload.path[0]==feeTokenAddress, - "tokenIn must be UST" + payload.path[0]==FEE_TOKEN_ADDRESS, + "tokenIn must be feeToken" ); require( - payload.path[1]==wrappedNative, + payload.path[1]==WRAPPED_NATIVE, "tokenOut must be wrapped Native" ); // pay relayer before attempting to do the swap // reflect payment in second swap amount - IERC20 feeToken = IERC20(feeTokenAddress); + IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); feeToken.safeTransfer(msg.sender, payload.relayerFee); uint256 swapAmountLessFees = payload.swapAmount - payload.relayerFee; // approve the router to spend tokens TransferHelper.safeApprove( payload.path[0], - address(swapRouter), + address(SWAP_ROUTER), swapAmountLessFees ); @@ -148,9 +122,9 @@ contract CrossChainSwapV3 { }); // try to execute the swap - try swapRouter.exactInputSingle(params) returns (uint256 amountOut) { + try SWAP_ROUTER.exactInputSingle(params) returns (uint256 amountOut) { // unwrap native and send to recipient - IWETH(wrappedNative).withdraw(amountOut); + IWETH(WRAPPED_NATIVE).withdraw(amountOut); payable(payload.recipientAddress).transfer(amountOut); // used in UI to tell user they're getting @@ -164,14 +138,14 @@ contract CrossChainSwapV3 { ); return amountOut; } catch { - // swap failed - return UST to recipient - IERC20(feeTokenAddress).safeTransfer( + // swap failed - return feeToken to recipient + IERC20(FEE_TOKEN_ADDRESS).safeTransfer( payload.recipientAddress, swapAmountLessFees ); // used in UI to tell user they're getting - // UST instead of their desired native asset + // feeToken instead of their desired native asset emit SwapResult( payload.recipientAddress, payload.path[0], @@ -190,23 +164,22 @@ contract CrossChainSwapV3 { SwapHelper.DecodedVaaParameters memory payload = _getParsedPayload( encodedVaa, - typeExactOut, - typeNativeSwap + TypeExactOut ); // sanity check path require( - payload.path[0]==feeTokenAddress, - "tokenIn must be UST" + payload.path[0]==FEE_TOKEN_ADDRESS, + "tokenIn must be feeToken" ); require( - payload.path[1]==wrappedNative, + payload.path[1]==WRAPPED_NATIVE, "tokenOut must be wrapped native asset" ); // pay relayer before attempting to do the swap // reflect payment in second swap amount - IERC20 feeToken = IERC20(feeTokenAddress); + IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); feeToken.safeTransfer(msg.sender, payload.relayerFee); uint256 maxAmountInLessFees = payload.swapAmount - payload.relayerFee; @@ -216,7 +189,7 @@ contract CrossChainSwapV3 { // approve the router to spend tokens TransferHelper.safeApprove( payload.path[0], - address(swapRouter), + address(SWAP_ROUTER), maxAmountInLessFees ); @@ -234,22 +207,22 @@ contract CrossChainSwapV3 { }); // try to perform the swap - try swapRouter.exactOutputSingle(params) returns (uint256 amountInUsed) { - // refund recipient with any UST not used in the swap + try SWAP_ROUTER.exactOutputSingle(params) returns (uint256 amountInUsed) { + // refund recipient with any feeToken not used in the swap if (amountInUsed < maxAmountInLessFees) { TransferHelper.safeApprove( - feeTokenAddress, - address(swapRouter), + FEE_TOKEN_ADDRESS, + address(SWAP_ROUTER), 0 ); - IERC20(feeTokenAddress).safeTransfer( + IERC20(FEE_TOKEN_ADDRESS).safeTransfer( payload.recipientAddress, maxAmountInLessFees - amountInUsed ); } // unwrap native and send to recipient - IWETH(wrappedNative).withdraw(amountOut); + IWETH(WRAPPED_NATIVE).withdraw(amountOut); payable(payload.recipientAddress).transfer(amountOut); // used in UI to tell user they're getting @@ -263,14 +236,14 @@ contract CrossChainSwapV3 { ); return amountInUsed; } catch { - // swap failed - return UST to recipient - IERC20(feeTokenAddress).safeTransfer( + // swap failed - return feeToken to recipient + IERC20(FEE_TOKEN_ADDRESS).safeTransfer( payload.recipientAddress, maxAmountInLessFees ); // used in UI to tell user they're getting - // UST instead of their desired native asset + // feeToken instead of their desired native asset emit SwapResult( payload.recipientAddress, payload.path[0], @@ -281,30 +254,15 @@ contract CrossChainSwapV3 { } } - /// @dev Executes exactIn native asset and token swaps before - /// sending a custom payload to the TokenBridge + /// @dev Executes exactIn native asset swap function _swapExactInBeforeTransfer( uint256 amountIn, uint256 amountOutMinimum, address contractCaller, address[] calldata path, uint256 deadline, - uint24 poolFee, - uint8 swapType + uint24 poolFee ) internal returns (uint256 amountOut) { - if (swapType == typeTokenSwap) { - // transfer the allowed amount of tokens to this contract - IERC20 token = IERC20(path[0]); - token.safeTransferFrom(contractCaller, address(this), amountIn); - - // approve the router to spend tokens - TransferHelper.safeApprove( - path[0], - address(swapRouter), - amountIn - ); - } - // set swap options with user params ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({ @@ -319,11 +277,7 @@ contract CrossChainSwapV3 { }); // perform the swap - if (swapType == typeTokenSwap) { - amountOut = swapRouter.exactInputSingle(params); - } else { // native swap - amountOut = swapRouter.exactInputSingle{value: amountIn}(params); - } + amountOut = SWAP_ROUTER.exactInputSingle{value: amountIn}(params); } /// @dev Calls _swapExactInBeforeTransfer and encodes custom payload with @@ -341,12 +295,12 @@ contract CrossChainSwapV3 { "insufficient amountOutMinimum to pay relayer" ); require( - path[0]==wrappedNative, + path[0]==WRAPPED_NATIVE, "tokenIn must be wrapped native asset for first swap" ); require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" + path[1]==FEE_TOKEN_ADDRESS, + "tokenOut must be feeToken for first swap" ); require(msg.value > 0, "must pass non 0 native asset amount"); @@ -357,8 +311,7 @@ contract CrossChainSwapV3 { msg.sender, path[0:2], swapParams.deadline, - swapParams.poolFee, - typeNativeSwap + swapParams.poolFee ); // create payload with target swap instructions @@ -369,21 +322,20 @@ contract CrossChainSwapV3 { path[3], swapParams.deadline, swapParams.poolFee, - typeExactIn, - typeNativeSwap, + TypeExactIn, relayerFee ); - // approve token bridge to spend feeTokens (UST) + // approve token bridge to spend feeTokens TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, + FEE_TOKEN_ADDRESS, + TOKEN_BRIDGE_ADDRESS, amountOut ); // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, + TokenBridge(TOKEN_BRIDGE_ADDRESS).transferTokensWithPayload( + FEE_TOKEN_ADDRESS, amountOut, targetChainId, targetContractAddress, @@ -392,36 +344,15 @@ contract CrossChainSwapV3 { ); } - /// @dev Executes exactOut native asset and token swaps before - /// sending a custom payload to the TokenBridge + /// @dev Executes exactOut native asset swaps function _swapExactOutBeforeTransfer( uint256 amountOut, uint256 amountInMaximum, address contractCaller, address[] calldata path, uint256 deadline, - uint24 poolFee, - uint8 swapType - ) internal { - // create instance of erc20 token for token swaps - IERC20 token = IERC20(path[0]); - - if (swapType == typeTokenSwap) { - // transfer tokens to this contract - token.safeTransferFrom( - contractCaller, - address(this), - amountInMaximum - ); - - // approve the router to spend tokens - TransferHelper.safeApprove( - path[0], - address(swapRouter), - amountInMaximum - ); - } - + uint24 poolFee + ) internal { // set swap options with user params ISwapRouter.ExactOutputSingleParams memory params = ISwapRouter.ExactOutputSingleParams({ @@ -435,31 +366,18 @@ contract CrossChainSwapV3 { sqrtPriceLimitX96: 0 }); - if (swapType == typeTokenSwap) { - // executes the swap returning the amountInUsed - uint256 amountInUsed = swapRouter.exactOutputSingle(params); + // executes the swap returning the amountInUsed + // ask for our money back -_- after the swap executes + uint256 amountInUsed = SWAP_ROUTER.exactOutputSingle{value: amountInMaximum}(params); + SWAP_ROUTER.refundETH(); - // return any amountIn not used in the swap to contractCaller - if (amountInUsed < amountInMaximum) { - TransferHelper.safeApprove(path[0], address(swapRouter), 0); - token.safeTransfer( - contractCaller, - amountInMaximum - amountInUsed - ); - } - } else { // native swap - // executes the swap returning the amountInUsed - // ask for our money back -_- after the swap executes - uint256 amountInUsed = swapRouter.exactOutputSingle{value: amountInMaximum}(params); - swapRouter.refundETH(); - - // return unused native asset to contractCaller - if (amountInUsed < amountInMaximum) { - TransferHelper.safeApprove(path[0], address(swapRouter), 0); - payable(contractCaller).transfer( - amountInMaximum - amountInUsed - ); - } + // return unused native asset to contractCaller + if (amountInUsed < amountInMaximum) { + // set SWAP_ROUTER allowance to zero + TransferHelper.safeApprove(path[0], address(SWAP_ROUTER), 0); + payable(contractCaller).transfer( + amountInMaximum - amountInUsed + ); } } @@ -478,12 +396,12 @@ contract CrossChainSwapV3 { "insufficient amountOut to pay relayer" ); require( - path[0]==wrappedNative, + path[0]==WRAPPED_NATIVE, "tokenIn must be wrapped native asset for first swap" ); require( - path[1]==feeTokenAddress, - "tokenOut must be UST for first swap" + path[1]==FEE_TOKEN_ADDRESS, + "tokenOut must be feeToken for first swap" ); require(msg.value > 0, "must pass non 0 native asset amount"); @@ -494,8 +412,7 @@ contract CrossChainSwapV3 { msg.sender, path[0:2], swapParams.deadline, - swapParams.poolFee, - typeNativeSwap + swapParams.poolFee ); // create payload with target swap instructions @@ -506,21 +423,20 @@ contract CrossChainSwapV3 { path[3], swapParams.deadline, swapParams.poolFee, - typeExactOut, - typeNativeSwap, + TypeExactOut, relayerFee ); - // approve token bridge to spend feeTokens (UST) + // approve token bridge to spend feeTokens TransferHelper.safeApprove( - feeTokenAddress, - tokenBridgeAddress, + FEE_TOKEN_ADDRESS, + TOKEN_BRIDGE_ADDRESS, swapParams.amountOut ); // send transfer with payload to the TokenBridge - TokenBridge(tokenBridgeAddress).transferTokensWithPayload( - feeTokenAddress, + TokenBridge(TOKEN_BRIDGE_ADDRESS).transferTokensWithPayload( + FEE_TOKEN_ADDRESS, swapParams.amountOut, targetChainId, targetContractAddress, diff --git a/contracts/contracts/IWormhole.sol b/contracts/contracts/shared/IWormhole.sol similarity index 100% rename from contracts/contracts/IWormhole.sol rename to contracts/contracts/shared/IWormhole.sol diff --git a/contracts/contracts/Structs.sol b/contracts/contracts/shared/Structs.sol similarity index 100% rename from contracts/contracts/Structs.sol rename to contracts/contracts/shared/Structs.sol diff --git a/contracts/contracts/SwapHelper.sol b/contracts/contracts/shared/SwapHelper.sol similarity index 95% rename from contracts/contracts/SwapHelper.sol rename to contracts/contracts/shared/SwapHelper.sol index c97ace3..1d4d670 100644 --- a/contracts/contracts/SwapHelper.sol +++ b/contracts/contracts/shared/SwapHelper.sol @@ -46,7 +46,6 @@ library SwapHelper { uint256 deadline; uint24 poolFee; uint8 swapFunctionType; - uint8 swapCurrencyType; uint256 relayerFee; } @@ -98,9 +97,6 @@ library SwapHelper { decoded.swapFunctionType = vmPayload.toUint8(index); index += 1; - decoded.swapCurrencyType = vmPayload.toUint8(index); - index += 1; - decoded.relayerFee = vmPayload.toUint256(index); index += 32; diff --git a/contracts/contracts/shared/TokenBridge.sol b/contracts/contracts/shared/TokenBridge.sol new file mode 100644 index 0000000..ea2b373 --- /dev/null +++ b/contracts/contracts/shared/TokenBridge.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.7.6; +pragma abicoder v2; + +interface TokenBridge { + function transferTokensWithPayload( + address token, + uint256 amount, + uint16 recipientChain, + bytes32 recipient, + uint32 nonce, + bytes memory payload + ) external payable returns (uint64); + function completeTransferWithPayload( + bytes memory encodedVm + ) external returns (bytes memory); +} \ No newline at end of file diff --git a/contracts/contracts/shared/WETH.sol b/contracts/contracts/shared/WETH.sol new file mode 100644 index 0000000..4785797 --- /dev/null +++ b/contracts/contracts/shared/WETH.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.7.6; +pragma abicoder v2; + +import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; + +interface IWETH is IERC20 { + function deposit() external payable; + function withdraw(uint amount) external; +} \ No newline at end of file From 162dd6ce9e4a031fb6a1e13229994e0992ed042a Mon Sep 17 00:00:00 2001 From: Drew Date: Fri, 1 Jul 2022 17:52:56 +0000 Subject: [PATCH 7/8] Add native relayer payment for exactIn swaps --- contracts/contracts/CrossChainSwapV2.sol | 34 +++++++++++---------- contracts/contracts/CrossChainSwapV3.sol | 38 +++++++++++++----------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/contracts/contracts/CrossChainSwapV2.sol b/contracts/contracts/CrossChainSwapV2.sol index 4e25c32..e0591a5 100644 --- a/contracts/contracts/CrossChainSwapV2.sol +++ b/contracts/contracts/CrossChainSwapV2.sol @@ -96,30 +96,31 @@ contract CrossChainSwapV2 { "tokenOut must be wrapped native asset" ); - // pay relayer before attempting to do the swap - // reflect payment in second swap amount - IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); - feeToken.safeTransfer(msg.sender, payload.relayerFee); - uint256 swapAmountLessFees = payload.swapAmount - payload.relayerFee; - // approve the router to spend tokens TransferHelper.safeApprove( uniPath[0], address(SWAP_ROUTER), - swapAmountLessFees + payload.swapAmount ); // try to execute the swap try SWAP_ROUTER.swapExactTokensForTokens( - swapAmountLessFees, + payload.swapAmount, payload.estimatedAmount, uniPath, address(this), payload.deadline ) returns (uint256[] memory amounts) { + // calculate how much to pay the relayer in the native token + uint256 nativeRelayerFee = amounts[1] * payload.relayerFee / payload.swapAmount; + uint256 nativeAmountOut = amounts[1] - nativeRelayerFee; + // unwrap native and send to recipient IWETH(WRAPPED_NATIVE).withdraw(amounts[1]); - payable(payload.recipientAddress).transfer(amounts[1]); + payable(payload.recipientAddress).transfer(nativeAmountOut); + + /// pay the relayer in the native token + payable(msg.sender).transfer(nativeRelayerFee); // used in UI to tell user they're getting // their desired token @@ -127,15 +128,19 @@ contract CrossChainSwapV2 { payload.recipientAddress, uniPath[1], msg.sender, - amounts[1], + nativeAmountOut, 1 ); return amounts; } catch { + // pay relayer in the feeToken since the swap failed + IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); + feeToken.safeTransfer(msg.sender, payload.relayerFee); + // swap failed - return feeToken to recipient - IERC20(FEE_TOKEN_ADDRESS).safeTransfer( + feeToken.safeTransfer( payload.recipientAddress, - swapAmountLessFees + payload.swapAmount - payload.relayerFee ); // used in UI to tell user they're getting @@ -144,7 +149,7 @@ contract CrossChainSwapV2 { payload.recipientAddress, uniPath[0], msg.sender, - swapAmountLessFees, + payload.swapAmount - payload.relayerFee, 0 ); } @@ -176,8 +181,7 @@ contract CrossChainSwapV2 { "tokenOut must be wrapped native asset" ); - // pay relayer before attempting to do the swap - // reflect payment in second swap amount + // pay the relayer in feeToken so that user gets desired exact amount out IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); feeToken.safeTransfer(msg.sender, payload.relayerFee); uint256 maxAmountInLessFees = payload.swapAmount - payload.relayerFee; diff --git a/contracts/contracts/CrossChainSwapV3.sol b/contracts/contracts/CrossChainSwapV3.sol index aa9421a..af5202b 100644 --- a/contracts/contracts/CrossChainSwapV3.sol +++ b/contracts/contracts/CrossChainSwapV3.sol @@ -93,19 +93,13 @@ contract CrossChainSwapV3 { require( payload.path[1]==WRAPPED_NATIVE, "tokenOut must be wrapped Native" - ); - - // pay relayer before attempting to do the swap - // reflect payment in second swap amount - IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); - feeToken.safeTransfer(msg.sender, payload.relayerFee); - uint256 swapAmountLessFees = payload.swapAmount - payload.relayerFee; + ); // approve the router to spend tokens TransferHelper.safeApprove( payload.path[0], address(SWAP_ROUTER), - swapAmountLessFees + payload.swapAmount ); // set swap options with user params @@ -116,16 +110,23 @@ contract CrossChainSwapV3 { fee: payload.poolFee, recipient: address(this), deadline: payload.deadline, - amountIn: swapAmountLessFees, + amountIn: payload.swapAmount, amountOutMinimum: payload.estimatedAmount, sqrtPriceLimitX96: 0 }); // try to execute the swap try SWAP_ROUTER.exactInputSingle(params) returns (uint256 amountOut) { + // calculate how much to pay the relayer in the native token + uint256 nativeRelayerFee = amountOut * payload.relayerFee / payload.swapAmount; + uint256 nativeAmountOut = amountOut - nativeRelayerFee; + // unwrap native and send to recipient IWETH(WRAPPED_NATIVE).withdraw(amountOut); - payable(payload.recipientAddress).transfer(amountOut); + payable(payload.recipientAddress).transfer(nativeAmountOut); + + /// pay the relayer in the native token + payable(msg.sender).transfer(nativeRelayerFee); // used in UI to tell user they're getting // their desired token @@ -133,15 +134,19 @@ contract CrossChainSwapV3 { payload.recipientAddress, payload.path[1], msg.sender, - amountOut, + nativeAmountOut, 1 ); return amountOut; } catch { - // swap failed - return feeToken to recipient - IERC20(FEE_TOKEN_ADDRESS).safeTransfer( + // pay relayer in the feeToken since the swap failed + IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); + feeToken.safeTransfer(msg.sender, payload.relayerFee); + + // swap failed - return feeToken (less relayer fees) to recipient + feeToken.safeTransfer( payload.recipientAddress, - swapAmountLessFees + payload.swapAmount - payload.relayerFee ); // used in UI to tell user they're getting @@ -150,7 +155,7 @@ contract CrossChainSwapV3 { payload.recipientAddress, payload.path[0], msg.sender, - swapAmountLessFees, + payload.swapAmount - payload.relayerFee, 0 ); } @@ -177,8 +182,7 @@ contract CrossChainSwapV3 { "tokenOut must be wrapped native asset" ); - // pay relayer before attempting to do the swap - // reflect payment in second swap amount + // pay the relayer in feeToken so that user gets desired exact amount out IERC20 feeToken = IERC20(FEE_TOKEN_ADDRESS); feeToken.safeTransfer(msg.sender, payload.relayerFee); uint256 maxAmountInLessFees = payload.swapAmount - payload.relayerFee; From f7ab415cf291b139900a82a78dc4d94fbce55fb4 Mon Sep 17 00:00:00 2001 From: Drew Date: Fri, 1 Jul 2022 20:36:07 +0000 Subject: [PATCH 8/8] Update relayer to handle new payload --- swap_relayer/src/evm.ts | 182 ++++---------------------------------- swap_relayer/src/index.ts | 116 +++++------------------- 2 files changed, 40 insertions(+), 258 deletions(-) diff --git a/swap_relayer/src/evm.ts b/swap_relayer/src/evm.ts index fe495fe..a3a0593 100644 --- a/swap_relayer/src/evm.ts +++ b/swap_relayer/src/evm.ts @@ -1,7 +1,4 @@ -import { - getIsTransferCompletedEth, - hexToUint8Array, -} from "@certusone/wormhole-sdk"; +import { getIsTransferCompletedEth, hexToUint8Array } from "@certusone/wormhole-sdk"; import { ethers } from "ethers"; @@ -54,35 +51,24 @@ export function loadEvmConfig(): EvmEnvironment[] { } let key_contract_address: string = evm + "_CONTRACT_ADDRESS"; - let val_contract_address: string = eval( - "process.env." + key_contract_address - ); + let val_contract_address: string = eval("process.env." + key_contract_address); if (!val_contract_address) { logger.error("Missing environment variable " + key_contract_address); return undefined; } let key_token_bridge_address: string = evm + "_TOKEN_BRIDGE_ADDRESS"; - let val_token_bridge_address: string = eval( - "process.env." + key_token_bridge_address - ); + let val_token_bridge_address: string = eval("process.env." + key_token_bridge_address); if (!val_token_bridge_address) { logger.error("Missing environment variable " + key_token_bridge_address); return undefined; } let key_wallet_private_key: string = evm + "_WALLET_PRIVATE_KEY"; - let val_wallet_private_key: string = eval( - "process.env." + key_wallet_private_key - ); - if (!val_wallet_private_key) - val_wallet_private_key = process.env.WALLET_PRIVATE_KEY; + let val_wallet_private_key: string = eval("process.env." + key_wallet_private_key); + if (!val_wallet_private_key) val_wallet_private_key = process.env.WALLET_PRIVATE_KEY; if (!val_wallet_private_key) { - logger.error( - "Missing environment variable " + - key_wallet_private_key + - " or WALLET_PRIVATE_KEY" - ); + logger.error("Missing environment variable " + key_wallet_private_key + " or WALLET_PRIVATE_KEY"); return undefined; } @@ -170,72 +156,15 @@ function makeContractDataForEvm(env: EvmEnvironment): EvmContractData { }; } -export function isEvmContract( - contractAddress: string, - chain_id: number -): boolean { +export function isEvmContract(contractAddress: string, chain_id: number): boolean { let ecd = evmContractData.get(chain_id); return ecd && ecd.contractAddress === contractAddress; } -/* - // GOERLI_PROVIDER = Ethereum - // MUMBAI_PROVIDER = Polygon - - if (t3Payload.contractAddress === CROSSCHAINSWAP_CONTRACT_ADDRESS_ETHEREUM) { - // Use one of the V3 swap methods. - } else if (t3Payload.contractAddress === CROSSCHAINSWAP_CONTRACT_ADDRESS_POLYGON) { - // Use one of the V2 swap methods. - } else { - // Error - } - - if (t3Payload.swapFunctionType === 1 && t3Payload.swapCurrencyType === 1) { - // swapExactInFromVaaNative - } else if (t3Payload.swapFunctionType === 1 && t3Payload.swapCurrencyType === 2) { - // swapExactInFromVaaToken - } else if ( - t3Payload.swapFunctionType === 2 && t3Payload.swapCurrencyType === 1) { - // swapExactOutFromVaaNative - } else if (t3Payload.swapFunctionType === 2 && t3Payload.swapCurrencyType === 2) { - // swapExactOutFromVaaToken - } else { - // error - } -*/ - -/* - // GOERLI_PROVIDER = Ethereum - // MUMBAI_PROVIDER = Polygon - - if (t3Payload.contractAddress === CROSSCHAINSWAP_CONTRACT_ADDRESS_ETHEREUM) { - // Use one of the V3 swap methods. - } else if (t3Payload.contractAddress === CROSSCHAINSWAP_CONTRACT_ADDRESS_POLYGON) { - // Use one of the V2 swap methods. - } else { - // Error - } - - if (t3Payload.swapFunctionType === 1 && t3Payload.swapCurrencyType === 1) { - // swapExactInFromVaaNative - } else if (t3Payload.swapFunctionType === 1 && t3Payload.swapCurrencyType === 2) { - // swapExactInFromVaaToken - } else if ( - t3Payload.swapFunctionType === 2 && t3Payload.swapCurrencyType === 1) { - // swapExactOutFromVaaNative - } else if (t3Payload.swapFunctionType === 2 && t3Payload.swapCurrencyType === 2) { - // swapExactOutFromVaaToken - } else { - // error - } -*/ - export async function relayVaaToEvm(vaaBytes: string, t3Payload: Type3Payload) { let ecd = evmContractData.get(t3Payload.targetChainId); if (!ecd) { - logger.error( - "relayVaaToEvm: chain id " + t3Payload.targetChainId + " does not exist!" - ); + logger.error("relayVaaToEvm: chain id " + t3Payload.targetChainId + " does not exist!"); } let exactIn: boolean = false; @@ -244,51 +173,23 @@ export async function relayVaaToEvm(vaaBytes: string, t3Payload: Type3Payload) { exactIn = true; } else if (t3Payload.swapFunctionType !== 2) { error = true; - logger.error( - "relayVaaTo" + - ecd.name + - ": unsupported swapFunctionType: [" + - t3Payload.swapFunctionType + - "]" - ); + logger.error("relayVaaTo" + ecd.name + ": unsupported swapFunctionType: [" + t3Payload.swapFunctionType + "]"); } - - let native: boolean = false; - if (t3Payload.swapCurrencyType === 1) { - native = true; - } else if (t3Payload.swapCurrencyType !== 2) { - error = true; - logger.error( - "relayVaaTo" + - ecd.name + - ": unsupported swapCurrencyType: [" + - t3Payload.swapCurrencyType + - "]" - ); - } - if (error) return; logger.debug( - "relayVaaTo" + - ecd.name + - ": chain_id: " + - ecd.chain_id + - ", contractAddress: [" + - t3Payload.contractAddress + - "]" + "relayVaaTo" + ecd.name + ": chain_id: " + ecd.chain_id + ", contractAddress: [" + t3Payload.contractAddress + "]" ); const signedVaaArray = hexToUint8Array(vaaBytes); - await relayVaaToEvmChain(t3Payload, ecd, signedVaaArray, exactIn, native); + await relayVaaToEvmChain(t3Payload, ecd, signedVaaArray, exactIn); } async function relayVaaToEvmChain( t3Payload: Type3Payload, tcd: EvmContractData, signedVaaArray: Uint8Array, - exactIn: boolean, - native: boolean + exactIn: boolean ) { logger.debug( "relayVaaTo" + @@ -312,8 +213,6 @@ async function relayVaaToEvmChain( t3Payload.contractAddress + "], exactIn: " + exactIn + - ", native: " + - native + ": completed: already transferred" ); @@ -331,41 +230,17 @@ async function relayVaaToEvmChain( t3Payload.contractAddress + "], exactIn: " + exactIn + - ", native: " + - native + ": submitting redeem request" ); try { let receipt: any = null; if (exactIn) { - if (native) { - logger.debug("relayVaaTo: calling evmSwapExactInFromVaaNative()"); - receipt = await swap.evmSwapExactInFromVaaNative( - tcd.contractWithSigner, - signedVaaArray - ); - } else { - logger.debug("relayVaaTo: calling evmSwapExactInFromVaaToken()"); - receipt = await swap.evmSwapExactInFromVaaToken( - tcd.contractWithSigner, - signedVaaArray - ); - } + logger.debug("relayVaaTo: calling evmSwapExactInFromVaaNative()"); + receipt = await swap.evmSwapExactInFromVaaNative(tcd.contractWithSigner, signedVaaArray); } else { - if (native) { - logger.debug("relayVaaTo: calling evmSwapExactOutFromVaaNative()"); - receipt = await swap.evmSwapExactOutFromVaaNative( - tcd.contractWithSigner, - signedVaaArray - ); - } else { - logger.debug("relayVaaTo: calling evmSwapExactOutFromVaaToken()"); - receipt = await swap.evmSwapExactOutFromVaaToken( - tcd.contractWithSigner, - signedVaaArray - ); - } + logger.debug("relayVaaTo: calling evmSwapExactOutFromVaaNative()"); + receipt = await swap.evmSwapExactOutFromVaaNative(tcd.contractWithSigner, signedVaaArray); } logger.info( @@ -379,8 +254,6 @@ async function relayVaaToEvmChain( t3Payload.contractAddress + "], exactIn: " + exactIn + - ", native: " + - native + ": completed: success, txHash: " + receipt.transactionHash ); @@ -397,8 +270,6 @@ async function relayVaaToEvmChain( t3Payload.contractAddress + "], exactIn: " + exactIn + - ", native: " + - native + ": completed: relay failed because the vaa has already been redeemed" ); @@ -412,8 +283,6 @@ async function relayVaaToEvmChain( t3Payload.contractAddress + "], exactIn: " + exactIn + - ", native: " + - native + ": transaction failed: %o", e ); @@ -431,8 +300,6 @@ async function relayVaaToEvmChain( t3Payload.contractAddress + "], exactIn: " + exactIn + - ", native: " + - native + ": redeem confirmed" ); } else { @@ -447,29 +314,18 @@ async function relayVaaToEvmChain( t3Payload.contractAddress + "], exactIn: " + exactIn + - ", native: " + - native + ": completed: failed to confirm redeem!" ); } } -async function isRedeemedOnEvm( - tcd: EvmContractData, - signedVaaArray: Uint8Array -): Promise { +async function isRedeemedOnEvm(tcd: EvmContractData, signedVaaArray: Uint8Array): Promise { let redeemed: boolean = false; try { - redeemed = await getIsTransferCompletedEth( - tcd.tokenBridgeAddress, - tcd.provider, - signedVaaArray - ); + redeemed = await getIsTransferCompletedEth(tcd.tokenBridgeAddress, tcd.provider, signedVaaArray); } catch (e) { logger.error( - "relayVaaTo" + - tcd.name + - ": failed to check if transfer is already complete, will attempt the transfer, e: %o", + "relayVaaTo" + tcd.name + ": failed to check if transfer is already complete, will attempt the transfer, e: %o", e ); } diff --git a/swap_relayer/src/index.ts b/swap_relayer/src/index.ts index 7d33294..b75ca98 100644 --- a/swap_relayer/src/index.ts +++ b/swap_relayer/src/index.ts @@ -12,33 +12,11 @@ import { getEmitterAddressTerra, } from "@certusone/wormhole-sdk"; -import { - importCoreWasm, - setDefaultWasm, -} from "@certusone/wormhole-sdk/lib/cjs/solana/wasm"; - -import { - createSpyRPCServiceClient, - subscribeSignedVAA, -} from "@certusone/wormhole-spydk"; - +import { importCoreWasm, setDefaultWasm } from "@certusone/wormhole-sdk/lib/cjs/solana/wasm"; +import { createSpyRPCServiceClient, subscribeSignedVAA } from "@certusone/wormhole-spydk"; import { ethers } from "ethers"; - -import { - EvmEnvironment, - isEvmContract, - loadEvmConfig, - makeEvmContractData, - relayVaaToEvm, -} from "./evm"; - -import { - isTerraContract, - loadTerraConfig, - makeTerraContractData, - relayVaaToTerra, - TerraEnvironment, -} from "./terra"; +import { EvmEnvironment, isEvmContract, loadEvmConfig, makeEvmContractData, relayVaaToEvm } from "./evm"; +import { isTerraContract, loadTerraConfig, makeTerraContractData, relayVaaToTerra, TerraEnvironment } from "./terra"; export let logger: any; @@ -66,7 +44,6 @@ export type Type3Payload = { contractAddress: string; relayerFee: ethers.BigNumber; swapFunctionType: number; - swapCurrencyType: number; }; type PendingEvent = { @@ -88,11 +65,7 @@ let condition = new CondVar(); let pendingQueue = new Array(); if (success) { - logger.info( - "swap_relayer starting up, will listen for signed VAAs from [" + - env.spy_host + - "]" - ); + logger.info("swap_relayer starting up, will listen for signed VAAs from [" + env.spy_host + "]"); try { makeEvmContractData(env.evm_configs); @@ -143,10 +116,7 @@ async function spy_listen() { var myFilters = []; for (var i = 0; i < parsedJsonFilters.length; i++) { var myChainId = parseInt(parsedJsonFilters[i].chain_id) as ChainId; - var myEmitterAddress = await encodeEmitterAddress( - myChainId, - parsedJsonFilters[i].emitter_address - ); + var myEmitterAddress = await encodeEmitterAddress(myChainId, parsedJsonFilters[i].emitter_address); var myEmitterFilter = { emitterFilter: { chainId: myChainId, @@ -182,10 +152,7 @@ async function spy_listen() { })(); } -async function encodeEmitterAddress( - myChainId, - emitterAddressStr -): Promise { +async function encodeEmitterAddress(myChainId, emitterAddressStr): Promise { if (myChainId === CHAIN_ID_SOLANA) { return await getEmitterAddressSolana(emitterAddressStr); } @@ -206,17 +173,11 @@ async function processVaa(vaaBytes: string) { let emitter_address: string = uint8ArrayToHex(parsedVAA.emitter_address); - let seqNumKey: string = - parsedVAA.emitter_chain.toString() + ":" + emitter_address; + let seqNumKey: string = parsedVAA.emitter_chain.toString() + ":" + emitter_address; let lastSeqNum = seqMap.get(seqNumKey); if (lastSeqNum) { if (lastSeqNum >= parsedVAA.sequence) { - logger.debug( - "ignoring duplicate: emitter: [" + - seqNumKey + - "], seqNum: " + - parsedVAA.sequence - ); + logger.debug("ignoring duplicate: emitter: [" + seqNumKey + "], seqNum: " + parsedVAA.sequence); return; } } @@ -248,8 +209,6 @@ async function processVaa(vaaBytes: string) { t3Payload.relayerFee + "], swapFunctionType: [" + t3Payload.swapFunctionType + - "], swapCurrencyType: [" + - t3Payload.swapCurrencyType + "]" ); @@ -270,8 +229,6 @@ async function processVaa(vaaBytes: string) { t3Payload.relayerFee + "], swapFunctionType: [" + t3Payload.swapFunctionType + - "], swapCurrencyType: [" + - t3Payload.swapCurrencyType + "]" ); } @@ -289,10 +246,7 @@ async function processVaa(vaaBytes: string) { } } -function decodeSignedVAAPayloadType3( - parsedVAA: any, - sourceChainId: number -): Type3Payload { +function decodeSignedVAAPayloadType3(parsedVAA: any, sourceChainId: number): Type3Payload { const payload = Buffer.from(new Uint8Array(parsedVAA.payload)); if (payload[0] !== 3) return undefined; @@ -310,18 +264,13 @@ function decodeSignedVAAPayloadType3( let contractAddress: string = ""; let swapFunctionType: number = 0; - let swapCurrencyType: number = 0; if (targetChainId === 3) { - logger.info( - "decodeSignedVAAPayloadType3: terraContractAddr: [" + - payload.slice(67, 67 + 32).toString("hex") + - "]" - ); + logger.info("decodeSignedVAAPayloadType3: terraContractAddr: [" + payload.slice(67, 67 + 32).toString("hex") + "]"); contractAddress = payload.slice(67, 67 + 32).toString("hex"); } else { - if (payload.length < 262) { + if (payload.length < 272) { logger.error( "decodeSignedVAAPayloadType3: dropping type 3 vaa because the payload is too short to extract the contract fields, length: " + payload.length + @@ -330,34 +279,24 @@ function decodeSignedVAAPayloadType3( ); return undefined; } - contractAddress = payload.slice(79, 79 + 20).toString("hex"); swapFunctionType = payload.readUInt8(272); - swapCurrencyType = payload.readUInt8(273); } return { sourceChainId: sourceChainId, targetChainId: targetChainId, contractAddress: contractAddress, - relayerFee: ethers.BigNumber.from(payload.slice(101, 101 + 32)), + relayerFee: ethers.BigNumber.from(payload.slice(273, 273 + 32)), swapFunctionType: swapFunctionType, - swapCurrencyType: swapCurrencyType, }; } function isOurContract(contractAddress: string, chainId: number): boolean { - return ( - isEvmContract(contractAddress, chainId) || - isTerraContract(contractAddress, chainId) - ); + return isEvmContract(contractAddress, chainId) || isTerraContract(contractAddress, chainId); } -async function postVaa( - vaaBytes: any, - t3Payload: Type3Payload, - receiveTime: Date -) { +async function postVaa(vaaBytes: any, t3Payload: Type3Payload, receiveTime: Date) { let event: PendingEvent = { vaaBytes: vaaBytes, t3Payload: t3Payload, @@ -366,9 +305,7 @@ async function postVaa( await mutex.runExclusive(() => { pendingQueue.push(event); - logger.debug( - "posting event, there are now " + pendingQueue.length + " enqueued events" - ); + logger.debug("posting event, there are now " + pendingQueue.length + " enqueued events"); if (condition) { logger.debug("hitting condition variable."); condition.complete(true); @@ -419,16 +356,12 @@ async function callBack(err: any, result: any) { await mutex.runExclusive(async () => { if (pendingQueue.length === 0) { - logger.debug( - "in callback, no more pending events, rearming the condition." - ); + logger.debug("in callback, no more pending events, rearming the condition."); done = true; condition = new CondVar(); await condition.wait(COND_VAR_TIMEOUT, callBack); } else { - logger.debug( - "in callback, there are " + pendingQueue.length + " pending events." - ); + logger.debug("in callback, there are " + pendingQueue.length + " pending events."); } }); } @@ -455,8 +388,7 @@ function initLogger() { let logFileName: string = ""; if (process.env.LOG_DIR) { useConsole = false; - logFileName = - process.env.LOG_DIR + "/swap_relay." + new Date().toISOString() + ".log"; + logFileName = process.env.LOG_DIR + "/swap_relay." + new Date().toISOString() + ".log"; } let logLevel = "info"; @@ -472,11 +404,7 @@ function initLogger() { level: logLevel, }); } else { - console.log( - "swap_relay is logging to [%s] at level [%s]", - logFileName, - logLevel - ); + console.log("swap_relay is logging to [%s] at level [%s]", logFileName, logLevel); transport = new winston.transports.File({ filename: logFileName, @@ -492,9 +420,7 @@ function initLogger() { winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss.SSS", }), - winston.format.printf( - (info: any) => `${[info.timestamp]}|${info.level}|${info.message}` - ) + winston.format.printf((info: any) => `${[info.timestamp]}|${info.level}|${info.message}`) ), };