Merge pull request #2 from certusone/evm-payload3-update

Update contracts to interact with new payload3 version
This commit is contained in:
dsterioti 2022-03-23 16:37:14 -05:00 committed by GitHub
commit af6fa376a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 196 additions and 99 deletions

View File

@ -23,8 +23,9 @@ interface TokenBridge {
bytes memory payload
) external payable returns (uint64);
function completeTransferWithPayload(
bytes memory encodedVm
) external returns (IWormhole.VM memory);
bytes memory encodedVm,
address feeRecipient
) external returns (bytes memory);
}
@ -77,21 +78,22 @@ contract CrossChainSwapV2 {
function _getParsedPayload(
bytes calldata encodedVaa,
uint8 swapFunctionType,
uint8 swapCurrencyType
uint8 swapCurrencyType,
address feeRecipient
) private returns (SwapHelper.DecodedVaaParameters memory payload) {
// complete the transfer on the token bridge
IWormhole.VM memory vm = TokenBridge(
bytes memory vmPayload = TokenBridge(
tokenBridgeAddress
).completeTransferWithPayload(encodedVaa);
).completeTransferWithPayload(encodedVaa, feeRecipient);
// make sure payload is the right size
require(
vm.payload.length==expectedVaaLength,
vmPayload.length==expectedVaaLength,
"VAA has the wrong number of bytes"
);
// parse the payload
payload = SwapHelper.decodeVaaPayload(vm);
payload = SwapHelper.decodeVaaPayload(vmPayload);
// sanity check payload parameters
require(
@ -108,14 +110,32 @@ 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
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;
// create dynamic address array
// uniswap won't take fixed size array
address[] memory uniPath = new address[](2);
@ -132,12 +152,6 @@ 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],
@ -169,7 +183,7 @@ contract CrossChainSwapV2 {
return amounts;
} catch {
// swap failed - return UST to recipient
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
swapAmountLessFees
);
@ -190,14 +204,32 @@ contract CrossChainSwapV2 {
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
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];
@ -206,14 +238,6 @@ contract CrossChainSwapV2 {
// make sure first element in path is UST
require(uniPath[0]==feeTokenAddress, "tokenIn must be UST");
// 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],
@ -241,7 +265,7 @@ contract CrossChainSwapV2 {
return amounts;
} catch {
// swap failed - return UST to recipient
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
swapAmountLessFees
);
@ -430,13 +454,31 @@ contract CrossChainSwapV2 {
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
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 maxAmountInLessFees = balanceAfter - balanceBefore;
// amountOut is the estimated swap amount for exact out methods
uint256 amountOut = payload.estimatedAmount;
@ -455,12 +497,6 @@ 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;
// approve the router to spend tokens
TransferHelper.safeApprove(
@ -487,7 +523,7 @@ contract CrossChainSwapV2 {
address(swapRouter),
0
);
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
maxAmountInLessFees - amountInUsed
);
@ -509,7 +545,7 @@ contract CrossChainSwapV2 {
return amountInUsed;
} catch {
// swap failed - return UST to recipient
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
maxAmountInLessFees
);
@ -530,13 +566,31 @@ contract CrossChainSwapV2 {
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
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;
@ -546,12 +600,6 @@ contract CrossChainSwapV2 {
uniPath[0] = payload.path[0];
uniPath[1] = payload.path[1];
require(uniPath[0]==feeTokenAddress, "tokenIn must be UST");
// 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;
// approve the router to spend tokens
TransferHelper.safeApprove(
@ -578,7 +626,7 @@ contract CrossChainSwapV2 {
address(swapRouter),
0
);
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
maxAmountInLessFees - amountInUsed
);
@ -596,7 +644,7 @@ contract CrossChainSwapV2 {
return amountInUsed;
} catch {
// swap failed - return UST to recipient
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
maxAmountInLessFees
);

View File

@ -23,8 +23,9 @@ interface TokenBridge {
bytes memory payload
) external payable returns (uint64);
function completeTransferWithPayload(
bytes memory encodedVm
) external returns (IWormhole.VM memory);
bytes memory encodedVm,
address feeRecipient
) external returns (bytes memory);
}
@ -81,21 +82,22 @@ contract CrossChainSwapV3 {
function _getParsedPayload(
bytes calldata encodedVaa,
uint8 swapFunctionType,
uint8 swapCurrencyType
uint8 swapCurrencyType,
address feeRecipient
) private returns (SwapHelper.DecodedVaaParameters memory payload) {
// complete the transfer on the token bridge
IWormhole.VM memory vm = TokenBridge(
bytes memory vmPayload = TokenBridge(
tokenBridgeAddress
).completeTransferWithPayload(encodedVaa);
).completeTransferWithPayload(encodedVaa, feeRecipient);
// make sure payload is the right size
require(
vm.payload.length==expectedVaaLength,
vmPayload.length==expectedVaaLength,
"VAA has the wrong number of bytes"
);
// parse the payload
payload = SwapHelper.decodeVaaPayload(vm);
payload = SwapHelper.decodeVaaPayload(vmPayload);
// sanity check payload parameters
require(
@ -112,14 +114,31 @@ contract CrossChainSwapV3 {
function recvAndSwapExactNativeIn(
bytes calldata encodedVaa
) external returns (uint256 amountOut) {
// redeem and fetch parsed payload
// 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));
SwapHelper.DecodedVaaParameters memory payload =
_getParsedPayload(
encodedVaa,
typeExactIn,
typeNativeSwap
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;
// sanity check path
require(
payload.path[0]==feeTokenAddress,
@ -130,12 +149,6 @@ 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],
@ -174,7 +187,7 @@ contract CrossChainSwapV3 {
return amountOut;
} catch {
// swap failed - return UST to recipient
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
swapAmountLessFees
);
@ -195,23 +208,35 @@ contract CrossChainSwapV3 {
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
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");
// 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],
@ -246,7 +271,7 @@ contract CrossChainSwapV3 {
return amountOut;
} catch {
// swap failed - return UST to recipient
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
swapAmountLessFees
);
@ -448,14 +473,32 @@ contract CrossChainSwapV3 {
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
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 maxAmountInLessFees = balanceAfter - balanceBefore;
// sanity check path
require(
payload.path[0]==feeTokenAddress,
@ -469,12 +512,6 @@ contract CrossChainSwapV3 {
// amountOut is the estimated swap amount for exact out methods
uint256 amountOut = payload.estimatedAmount;
// 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;
// approve the router to spend tokens
TransferHelper.safeApprove(
payload.path[0],
@ -504,7 +541,7 @@ contract CrossChainSwapV3 {
address(swapRouter),
0
);
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
maxAmountInLessFees - amountInUsed
);
@ -526,7 +563,7 @@ contract CrossChainSwapV3 {
return amountInUsed;
} catch {
// swap failed - return UST to recipient
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
maxAmountInLessFees
);
@ -547,13 +584,31 @@ contract CrossChainSwapV3 {
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
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;
// check path to see if first element is the feeToken
require(payload.path[0]==feeTokenAddress, "tokenIn must be UST");
@ -561,12 +616,6 @@ contract CrossChainSwapV3 {
// amountOut is the estimated swap amount for exact out methods
uint256 amountOut = payload.estimatedAmount;
// 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;
// approve the router to spend tokens
TransferHelper.safeApprove(
payload.path[0],
@ -596,7 +645,7 @@ contract CrossChainSwapV3 {
address(swapRouter),
0
);
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
maxAmountInLessFees - amountInUsed
);
@ -614,7 +663,7 @@ contract CrossChainSwapV3 {
return amountInUsed;
} catch {
// swap failed - return UST to recipient
feeToken.safeTransfer(
IERC20(feeTokenAddress).safeTransfer(
payload.recipientAddress,
maxAmountInLessFees
);

View File

@ -52,52 +52,52 @@ library SwapHelper {
/// @dev Decodes parameters encoded in a VAA
function decodeVaaPayload(
IWormhole.VM memory encodedVm
bytes memory vmPayload
) public view returns (DecodedVaaParameters memory decoded) {
uint index = 0;
decoded.version = encodedVm.payload.toUint8(index);
decoded.version = vmPayload.toUint8(index);
index += 1;
decoded.swapAmount = encodedVm.payload.toUint256(index);
decoded.swapAmount = vmPayload.toUint256(index);
index += 32;
// skip
index += 46;
decoded.contractAddress = encodedVm.payload.toAddress(index);
decoded.contractAddress = vmPayload.toAddress(index);
index += 20;
// skip
index += 2;
decoded.relayerFee = encodedVm.payload.toUint256(index);
decoded.relayerFee = vmPayload.toUint256(index);
index += 32;
decoded.estimatedAmount = encodedVm.payload.toUint256(index);
decoded.estimatedAmount = vmPayload.toUint256(index);
index += 44;
decoded.recipientAddress = encodedVm.payload.toAddress(index);
decoded.recipientAddress = vmPayload.toAddress(index);
index += 20;
decoded.path[0] = encodedVm.payload.toAddress(index);
decoded.path[0] = vmPayload.toAddress(index);
index += 20;
decoded.path[1] = encodedVm.payload.toAddress(index);
decoded.path[1] = vmPayload.toAddress(index);
index += 20;
decoded.deadline = encodedVm.payload.toUint256(index);
decoded.deadline = vmPayload.toUint256(index);
index += 32;
// skip
index += 1;
decoded.poolFee = encodedVm.payload.toUint16(index);
decoded.poolFee = vmPayload.toUint16(index);
index += 2;
decoded.swapFunctionType = encodedVm.payload.toUint8(index);
decoded.swapFunctionType = vmPayload.toUint8(index);
index += 1;
decoded.swapCurrencyType = encodedVm.payload.toUint8(index);
decoded.swapCurrencyType = vmPayload.toUint8(index);
}
}

View File

@ -1,4 +1,4 @@
#!/bin/bash
set -euo pipefail
npx truffle migrate --config truffle-config.ethereum.js --network goerli --reset
npx truffle migrate --config cfg/truffle-config.ethereum.js --network goerli --reset