Skip to content

Macro changes #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 25 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c7834ba
fix: restrict `_swapper` param in `directSwapperCall`
liu-zhipeng May 31, 2023
0dcfd0b
fix: no value is sent to `swapETH`
liu-zhipeng May 31, 2023
657c3fa
fix: consider the case that from == to
liu-zhipeng May 31, 2023
1181d3e
test: fix forge test
liu-zhipeng May 31, 2023
bb81761
fix: swapETH func of OneInchUniswapV3
liu-zhipeng May 31, 2023
4109eed
test: fix
liu-zhipeng May 31, 2023
520b5ce
fix: native asset lost on swapAndXcall
liu-zhipeng Jun 1, 2023
d06e99c
fix: minor issue
liu-zhipeng Jun 1, 2023
00725bb
doc: address(0) treatment for swapAndXcall
liu-zhipeng Jun 2, 2023
7680673
Merge pull request #19 from connext/macro-h6
LayneHaber Jun 29, 2023
8b0c6ae
Merge pull request #20 from connext/macro-h3
LayneHaber Jun 29, 2023
3c9cb12
Merge pull request #21 from connext/macro-h4
LayneHaber Jun 29, 2023
0d39664
Merge pull request #24 from connext/macro-h8
LayneHaber Jun 29, 2023
8f744cb
Merge pull request #26 from connext/macro-m4
LayneHaber Jun 29, 2023
33b1aee
fix: use SafeERC20 (#27)
liu-zhipeng Jun 29, 2023
46b4d30
fix: [macro-l3] add events and errors to swapAdapter (#30)
liu-zhipeng Jun 29, 2023
0a8a186
fix: add indexed to events (#31)
liu-zhipeng Jun 29, 2023
bd71354
Macro l2 (#38)
LayneHaber Jun 29, 2023
29bc789
fix: remove address(this) from allowedSwappers (#33)
liu-zhipeng Jun 29, 2023
69b0062
fix: use Ownable2Step (#34)
liu-zhipeng Jun 29, 2023
d334331
fix: unused Address library (#35)
liu-zhipeng Jun 29, 2023
bd0f4c0
doc: [macro-q12] missing natspec (#36)
liu-zhipeng Jun 29, 2023
b530fbb
fix: check msg.value == amounIn (#28)
liu-zhipeng Jul 7, 2023
ebd4084
fix: [macro-q4] add indexed to events (#32)
liu-zhipeng Jul 7, 2023
9c4eb68
fix: prevent msg.value if not eth swap (#25)
liu-zhipeng Jul 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
[submodule "hello_foundry/lib/forge-std"]
path = hello_foundry/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
branch = v1.5.1
[submodule "lib/vulcan"]
path = lib/vulcan
url = https://github.com/nomoixyz/vulcan
branch = alpha-1
tag = v0.1.0
[submodule "lib/connext-interfaces"]
path = lib/connext-interfaces
url = https://github.com/connext/interfaces
68 changes: 46 additions & 22 deletions contracts/destination/xreceivers/AuthForwarderXReceiver.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IConnext} from "@connext/interfaces/core/IConnext.sol";
import {IXReceiver} from "@connext/interfaces/core/IXReceiver.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
Expand All @@ -14,10 +15,12 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
* caveat that xReceive will fail until the AMB's validation window has elapsed. This is meant to be used when there
* are funds passed into the contract that need to be forwarded to another contract.
*
* This contract inherits OpenZeppelin's Ownable module which allows ownership to be changed with `transferOwnership`.
* For more details, see the implementation: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol
* This contract inherits OpenZeppelin's Ownable2Step module which allows ownership to be changed with `transferOwnership`.
* For more details, see the implementation: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable2Step.sol
*/
abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
abstract contract AuthForwarderXReceiver is IXReceiver, Ownable2Step {
using SafeERC20 for IERC20;

/// The Connext contract on this domain
IConnext public immutable connext;

Expand All @@ -29,19 +32,21 @@ abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
mapping(uint32 => address) public originRegistry;

/// EVENTS
event ForwardedFunctionCallFailed(bytes32 _transferId);
event ForwardedFunctionCallFailed(bytes32 _transferId, string _errorMessage);
event ForwardedFunctionCallFailed(bytes32 _transferId, uint _errorCode);
event ForwardedFunctionCallFailed(bytes32 _transferId, bytes _lowLevelData);
event OriginAdded(uint32 _originDomain, address _originSender);
event OriginRemoved(uint32 _originDomain);
event Prepared(bytes32 _transferId, bytes _data, uint256 _amount, address _asset);
event ForwardedFunctionCallFailed(bytes32 indexed _transferId);
event ForwardedFunctionCallFailed(bytes32 indexed _transferId, string _errorMessage);
event ForwardedFunctionCallFailed(bytes32 indexed _transferId, uint _errorCode);
event ForwardedFunctionCallFailed(bytes32 indexed _transferId, bytes _lowLevelData);
event OriginAdded(uint32 indexed _originDomain, address indexed _originSender);
event OriginRemoved(uint32 indexed _originDomain);
event Prepared(bytes32 indexed _transferId, bytes _data, uint256 _amount, address _asset);

/// ERRORS
error ForwarderXReceiver__onlyOrigin(uint32 originDomain, address originSender, address sender);
error ForwarderXReceiver__prepareAndForward_notThis(address sender);
error ForwarderXReceiver__constructor_mismatchingOriginArrayLengths(address sender);
error ForwarderXReceiver__removeOrigin_invalidOrigin(uint32 originDomain);
error ForwarderXReceiver__addOrigin_alreadySet(uint32 originDomain);
error ForwarderXReceiver__addOrigin_zeroSender();

/// MODIFIERS
/** @notice A modifier for authenticated calls.
Expand All @@ -66,15 +71,19 @@ abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
* @param _originSenders - Array of senders on origin domains that are expected to call xcall
*/
constructor(address _connext, uint32[] memory _originDomains, address[] memory _originSenders) {
if (_originDomains.length != _originSenders.length) {
uint256 len = _originDomains.length;
if (len != _originSenders.length) {
revert ForwarderXReceiver__constructor_mismatchingOriginArrayLengths(msg.sender);
}

connext = IConnext(_connext);

for (uint32 i = 0; i < _originDomains.length; i++) {
originDomains.push(_originDomains[i]);
originRegistry[_originDomains[i]] = _originSenders[i];
for (uint256 i; i < len; ) {
_addOrigin(_originDomains[i], _originSenders[i]);

unchecked {
++i;
}
}
}

Expand All @@ -83,7 +92,14 @@ abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
* @param _originDomain - Origin domain to be registered in the OriginRegistry
* @param _originSender - Sender on origin domain that is expected to call this contract
*/
function addOrigin(uint32 _originDomain, address _originSender) public onlyOwner {
function addOrigin(uint32 _originDomain, address _originSender) external onlyOwner {
_addOrigin(_originDomain, _originSender);
}

function _addOrigin(uint32 _originDomain, address _originSender) internal {
if (_originSender == address(0)) revert ForwarderXReceiver__addOrigin_zeroSender();
if (originRegistry[_originDomain] != address(0)) revert ForwarderXReceiver__addOrigin_alreadySet(_originDomain);

originDomains.push(_originDomain);
originRegistry[_originDomain] = _originSender;
emit OriginAdded(_originDomain, _originSender);
Expand All @@ -93,22 +109,26 @@ abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
* @dev Remove an origin domain from the originRegistry.
* @param _originDomain - Origin domain to be removed from the OriginRegistry
*/
function removeOrigin(uint32 _originDomain) public onlyOwner {
function removeOrigin(uint32 _originDomain) external onlyOwner {
uint256 len = originDomains.length;
// Assign an out-of-bounds index by default
uint32 indexToRemove = uint32(originDomains.length);
for (uint32 i = 0; i < originDomains.length; i++) {
uint256 indexToRemove = len;
for (uint256 i; i < len; ) {
if (originDomains[i] == _originDomain) {
indexToRemove = i;
break;
}
unchecked {
++i;
}
}

if (indexToRemove >= uint32(originDomains.length)) {
if (indexToRemove == len) {
revert ForwarderXReceiver__removeOrigin_invalidOrigin(_originDomain);
}

// Constant operation to remove origin since we don't need to preserve order
originDomains[indexToRemove] = originDomains[originDomains.length - 1];
originDomains[indexToRemove] = originDomains[len - 1];
originDomains.pop();

delete originRegistry[_originDomain];
Expand All @@ -124,6 +144,7 @@ abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
* @param _amount - The amount of funds received in this transfer
* @param _asset - The asset of the funds received in this transfer
* @param _callData - The data to be prepared and forwarded
* @return the success status of the forwardFunctionCall
*/
function xReceive(
bytes32 _transferId,
Expand Down Expand Up @@ -161,7 +182,7 @@ abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
emit ForwardedFunctionCallFailed(_transferId, _lowLevelData);
}
if (!successfulForward) {
IERC20(_asset).transfer(_fallbackAddress, _amount);
SafeERC20.safeTransfer(IERC20(_asset), _fallbackAddress, _amount);
}
// Return the success status of the forwardFunctionCall
return abi.encode(successfulForward);
Expand All @@ -179,6 +200,7 @@ abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
* @param _data - The data to be prepared
* @param _amount - The amount of funds received in this transfer
* @param _asset - The asset of the funds received in this transfer
* @return The result of the forward Function call
*/
function prepareAndForward(
bytes32 _transferId,
Expand Down Expand Up @@ -209,6 +231,7 @@ abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
* @param _data - The data to be prepared
* @param _amount - The amount of funds received in this transfer
* @param _asset - The asset of the funds received in this transfer
* @return encoded data
*/
function _prepare(
bytes32 _transferId,
Expand All @@ -229,6 +252,7 @@ abstract contract AuthForwarderXReceiver is IXReceiver, Ownable {
* @param _transferId - The transfer ID of the transfer that triggered this call
* @param _amount - The amount of funds received in this transfer
* @param _asset - The asset of the funds received in this transfer
* @return the result of the call
*/
function _forwardFunctionCall(
bytes memory _preparedData,
Expand Down
19 changes: 13 additions & 6 deletions contracts/destination/xreceivers/ForwarderXReceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.0;

import {IConnext} from "@connext/interfaces/core/IConnext.sol";
import {IXReceiver} from "@connext/interfaces/core/IXReceiver.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
Expand All @@ -13,15 +14,17 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
* This is meant to be used when there are funds passed into the contract that need to be forwarded to another contract.
*/
abstract contract ForwarderXReceiver is IXReceiver {
using SafeERC20 for IERC20;

// The Connext contract on this domain
IConnext public immutable connext;

/// EVENTS
event ForwardedFunctionCallFailed(bytes32 _transferId);
event ForwardedFunctionCallFailed(bytes32 _transferId, string _errorMessage);
event ForwardedFunctionCallFailed(bytes32 _transferId, uint _errorCode);
event ForwardedFunctionCallFailed(bytes32 _transferId, bytes _lowLevelData);
event Prepared(bytes32 _transferId, bytes _data, uint256 _amount, address _asset);
event ForwardedFunctionCallFailed(bytes32 indexed _transferId);
event ForwardedFunctionCallFailed(bytes32 indexed _transferId, string _errorMessage);
event ForwardedFunctionCallFailed(bytes32 indexed _transferId, uint _errorCode);
event ForwardedFunctionCallFailed(bytes32 indexed _transferId, bytes _lowLevelData);
event Prepared(bytes32 indexed _transferId, bytes _data, uint256 _amount, address _asset);

/// ERRORS
error ForwarderXReceiver__onlyConnext(address sender);
Expand Down Expand Up @@ -55,6 +58,7 @@ abstract contract ForwarderXReceiver is IXReceiver {
* @param _amount - The amount of funds received in this transfer.
* @param _asset - The asset of the funds received in this transfer.
* @param _callData - The data to be prepared and forwarded. Fallback address needs to be encoded in the data to be used in case the forward fails.
* @return the success status of the forwardFunctionCall
*/
function xReceive(
bytes32 _transferId,
Expand Down Expand Up @@ -92,7 +96,7 @@ abstract contract ForwarderXReceiver is IXReceiver {
emit ForwardedFunctionCallFailed(_transferId, _lowLevelData);
}
if (!successfulForward) {
IERC20(_asset).transfer(_fallbackAddress, _amount);
SafeERC20.safeTransfer(IERC20(_asset), _fallbackAddress, _amount);
}
// Return the success status of the forwardFunctionCall
return abi.encode(successfulForward);
Expand All @@ -110,6 +114,7 @@ abstract contract ForwarderXReceiver is IXReceiver {
* @param _data - The data to be prepared
* @param _amount - The amount of funds received in this transfer
* @param _asset - The asset of the funds received in this transfer
* @return The result of the forward Function call
*/
function prepareAndForward(
bytes32 _transferId,
Expand Down Expand Up @@ -140,6 +145,7 @@ abstract contract ForwarderXReceiver is IXReceiver {
* @param _data - The data to be prepared
* @param _amount - The amount of funds received in this transfer
* @param _asset - The asset of the funds received in this transfer
* @return encoded data
*/
function _prepare(
bytes32 _transferId,
Expand All @@ -160,6 +166,7 @@ abstract contract ForwarderXReceiver is IXReceiver {
* @param _transferId - The transfer ID of the transfer that triggered this call
* @param _amount - The amount of funds received in this transfer
* @param _asset - The asset of the funds received in this transfer
* @return the result of the call
*/
function _forwardFunctionCall(
bytes memory _preparedData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ pragma solidity ^0.8.13;

import {IUniswapV2Router02} from "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import {TransferHelper} from "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {ForwarderXReceiver} from "../ForwarderXReceiver.sol";
import {SwapAdapter} from "../../../shared/Swap/SwapAdapter.sol";
Expand All @@ -14,8 +13,6 @@ import {SwapAdapter} from "../../../shared/Swap/SwapAdapter.sol";
* @notice Abstract contract to allow for swapping tokens before forwarding a call.
*/
abstract contract SwapForwarderXReceiver is ForwarderXReceiver, SwapAdapter {
using Address for address;

/// @dev The address of the Connext contract on this domain.
constructor(address _connext) ForwarderXReceiver(_connext) {}

Expand All @@ -27,6 +24,7 @@ abstract contract SwapForwarderXReceiver is ForwarderXReceiver, SwapAdapter {
* @param _data The data to be swapped.
* @param _amount The amount to be swapped.
* @param _asset The incoming asset to be swapped.
* @return prepared data
*/
function _prepare(
bytes32 _transferId,
Expand Down
22 changes: 15 additions & 7 deletions contracts/origin/Swap/SwapAndXCall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ contract SwapAndXCall is SwapAdapter {
* @notice Calls a swapper contract and then calls xcall on connext
* @dev Data for the swap is generated offchain to call to the appropriate swapper contract
* Function is payable since it uses the relayer fee in native asset
* @param _fromAsset Address of the asset to swap from
* @param _toAsset Address of the asset to swap to
* @param _fromAsset Address of the asset to swap from. fromAsset can be both of ETH and ERC20
* @param _toAsset Address of the asset to swap to. toAsset can't be ETH. because connext doesn't support xcall with ETH
* @param _amountIn Amount of the asset to swap from
* @param _swapper Address of the swapper contract
* @param _swapData Data to call the swapper contract with
Expand All @@ -43,11 +43,14 @@ contract SwapAndXCall is SwapAdapter {
uint256 _slippage,
bytes calldata _callData
) external payable {
uint256 amountOut = _fromAsset == address(0)
require(_toAsset != address(0), "connext not support");

bool isNative = _fromAsset == address(0);
uint256 amountOut = isNative
? _setupAndSwapETH(_toAsset, _amountIn, _swapper, _swapData)
: _setupAndSwap(_fromAsset, _toAsset, _amountIn, _swapper, _swapData);

connext.xcall{value: _fromAsset == address(0) ? msg.value - _amountIn : msg.value}(
connext.xcall{value: isNative ? msg.value - _amountIn : msg.value}(
_destination,
_to,
_toAsset,
Expand All @@ -62,8 +65,8 @@ contract SwapAndXCall is SwapAdapter {
* @notice Calls a swapper contract and then calls xcall on connext
* @dev Data for the swap is generated offchain to call to the appropriate swapper contract
* Pays relayer fee from the input asset
* @param _fromAsset Address of the asset to swap from
* @param _toAsset Address of the asset to swap to
* @param _fromAsset Address of the asset to swap from. fromAsset can be both of ETH and ERC20
* @param _toAsset Address of the asset to swap to. toAsset can't be ETH. because connext doesn't support xcall with ETH
* @param _amountIn Amount of the asset to swap from
* @param _swapper Address of the swapper contract
* @param _swapData Data to call the swapper contract with
Expand All @@ -87,7 +90,12 @@ contract SwapAndXCall is SwapAdapter {
bytes calldata _callData,
uint256 _relayerFee
) external payable {
uint256 amountOut = _fromAsset == address(0)
require(_toAsset != address(0), "connext not support");

bool isNative = _fromAsset == address(0);
require(msg.value == (isNative ? _amountIn : 0), "!value");

uint256 amountOut = isNative
? _setupAndSwapETH(_toAsset, _amountIn, _swapper, _swapData)
: _setupAndSwap(_fromAsset, _toAsset, _amountIn, _swapper, _swapData);

Expand Down
Loading