编译器
0.8.16+commit.07a7930e
文件 1 的 20:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 20:IDiamondCut.sol
pragma solidity 0.8.16;
interface IDiamondCut {
enum FacetCutAction {
Add,
Replace,
Remove
}
struct FacetCut {
address facetAddress;
FacetCutAction action;
bytes4[] functionSelectors;
}
function diamondCut(
FacetCut[] calldata _diamondCut,
address _init,
bytes calldata _calldata
) external;
event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}
文件 3 的 20:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 4 的 20:IRango.sol
pragma solidity 0.8.16;
interface IRango {
struct RangoBridgeRequest {
address requestId;
address token;
uint amount;
uint platformFee;
uint affiliateFee;
address payable affiliatorAddress;
uint destinationExecutorFee;
uint16 dAppTag;
}
enum BridgeType {Across, CBridge, Hop, Hyphen, Multichain, Stargate, Synapse, Thorchain, Symbiosis, Axelar, Voyager, Poly, OptimismBridge, ArbitrumBridge, Wormhole, AllBridge}
enum CrossChainOperationStatus {
Succeeded,
RefundInSource,
RefundInDestination,
SwapFailedInDestination
}
event RangoBridgeInitiated(
address indexed requestId,
address bridgeToken,
uint256 bridgeAmount,
address receiver,
uint destinationChainId,
bool hasInterchainMessage,
bool hasDestinationSwap,
uint8 indexed bridgeId,
uint16 indexed dAppTag
);
event RangoBridgeCompleted(
address indexed requestId,
address indexed token,
address indexed originalSender,
address receiver,
uint amount,
CrossChainOperationStatus status,
uint16 dAppTag
);
}
文件 5 的 20:IRangoMessageReceiver.sol
pragma solidity 0.8.16;
interface IRangoMessageReceiver {
enum ProcessStatus { SUCCESS, REFUND_IN_SOURCE, REFUND_IN_DESTINATION }
function handleRangoMessage(
address token,
uint amount,
ProcessStatus status,
bytes memory message
) external;
}
文件 6 的 20:IRangoStargate.sol
pragma solidity 0.8.16;
import "./IStargateRouter.sol";
import "./Interchain.sol";
import "./IRango.sol";
import "../libraries/LibSwapper.sol";
interface IRangoStargate {
enum StargateBridgeType {TRANSFER, TRANSFER_WITH_MESSAGE}
struct StargateRequest {
StargateBridgeType bridgeType;
uint16 dstChainId;
uint256 srcPoolId;
uint256 dstPoolId;
address payable srcGasRefundAddress;
uint256 minAmountLD;
uint256 dstGasForCall;
uint256 dstNativeAmount;
bytes dstNativeAddr;
bytes to;
uint stgFee;
bytes imMessage;
}
function stargateSwapAndBridge(
LibSwapper.SwapRequest memory request,
LibSwapper.Call[] calldata calls,
IRangoStargate.StargateRequest memory stargateRequest
) external payable;
function stargateBridge(
IRangoStargate.StargateRequest memory stargateRequest,
IRango.RangoBridgeRequest memory bridgeRequest
) external payable;
}
文件 7 的 20:IStargateReceiver.sol
pragma solidity 0.8.16;
interface IStargateReceiver {
function sgReceive(
uint16 chainId,
bytes memory srcAddress,
uint256 nonce,
address token,
uint256 amountLD,
bytes memory payload
) payable external;
}
文件 8 的 20:IStargateRouter.sol
pragma solidity 0.8.16;
interface IStargateRouter {
struct lzTxObj {
uint256 dstGasForCall;
uint256 dstNativeAmount;
bytes dstNativeAddr;
}
function swap(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLD,
uint256 _minAmountLD,
lzTxObj memory _lzTxParams,
bytes calldata _to,
bytes calldata _payload
) external payable;
function swapETH(
uint16 _dstChainId,
address payable _refundAddress,
bytes calldata _toAddress,
uint256 _amountLD,
uint256 _minAmountLD
) external payable;
function quoteLayerZeroFee(
uint16 _dstChainId,
uint8 _functionType,
bytes calldata _toAddress,
bytes calldata _transferAndCallPayload,
lzTxObj memory _lzTxParams
) external view returns (uint256, uint256);
}
文件 9 的 20:IUniswapV2.sol
pragma solidity 0.8.16;
interface IUniswapV2 {
function swapExactETHForTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable returns (uint[] memory amounts);
function swapExactAVAXForTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}
文件 10 的 20:IUniswapV3.sol
pragma solidity 0.8.16;
interface IUniswapV3 {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}
文件 11 的 20:IWETH.sol
pragma solidity 0.8.16;
interface IWETH {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 12 的 20:Interchain.sol
pragma solidity 0.8.16;
interface Interchain {
enum ActionType { NO_ACTION, UNI_V2, UNI_V3, CALL }
enum CallSubActionType { WRAP, UNWRAP, NO_ACTION }
struct RangoInterChainMessage {
address requestId;
uint64 dstChainId;
address bridgeRealOutput;
address toToken;
address originalSender;
address recipient;
ActionType actionType;
bytes action;
CallSubActionType postAction;
uint16 dAppTag;
bytes dAppMessage;
address dAppSourceContract;
address dAppDestContract;
}
struct UniswapV2Action {
address dexAddress;
uint amountOutMin;
address[] path;
uint deadline;
}
struct UniswapV3ActionExactInputSingleParams {
address dexAddress;
address tokenIn;
address tokenOut;
uint24 fee;
uint256 deadline;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
struct CallAction {
address tokenIn;
address spender;
CallSubActionType preAction;
address payable target;
bytes callData;
}
}
文件 13 的 20:LibDiamond.sol
pragma solidity 0.8.16;
import { IDiamondCut } from "../interfaces/IDiamondCut.sol";
library LibDiamond {
bytes32 internal constant DIAMOND_STORAGE_POSITION = hex"c8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c";
error IncorrectFacetCutAction();
error NoSelectorsInFacet();
error FunctionAlreadyExists();
error FacetAddressIsZero();
error FacetAddressIsNotZero();
error FacetContainsNoCode();
error FunctionDoesNotExist();
error FunctionIsImmutable();
error InitZeroButCalldataNotEmpty();
error CalldataEmptyButInitNotZero();
error InitReverted();
struct FacetAddressAndPosition {
address facetAddress;
uint96 functionSelectorPosition;
}
struct FacetFunctionSelectors {
bytes4[] functionSelectors;
uint256 facetAddressPosition;
}
struct DiamondStorage {
mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
address[] facetAddresses;
mapping(bytes4 => bool) supportedInterfaces;
address contractOwner;
}
function diamondStorage() internal pure returns (DiamondStorage storage ds) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
ds.slot := position
}
}
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function setContractOwner(address _newOwner) internal {
DiamondStorage storage ds = diamondStorage();
address previousOwner = ds.contractOwner;
ds.contractOwner = _newOwner;
emit OwnershipTransferred(previousOwner, _newOwner);
}
function contractOwner() internal view returns (address contractOwner_) {
contractOwner_ = diamondStorage().contractOwner;
}
function enforceIsContractOwner() internal view {
require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
}
event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
function diamondCut(
IDiamondCut.FacetCut[] memory _diamondCut,
address _init,
bytes memory _calldata
) internal {
for (uint256 facetIndex; facetIndex < _diamondCut.length; ) {
IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
if (action == IDiamondCut.FacetCutAction.Add) {
addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
} else if (action == IDiamondCut.FacetCutAction.Replace) {
replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
} else if (action == IDiamondCut.FacetCutAction.Remove) {
removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
} else {
revert IncorrectFacetCutAction();
}
unchecked {
++facetIndex;
}
}
emit DiamondCut(_diamondCut, _init, _calldata);
initializeDiamondCut(_init, _calldata);
}
function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
if (_facetAddress == address(0)) {
revert FacetAddressIsZero();
}
if (_functionSelectors.length == 0) {
revert NoSelectorsInFacet();
}
DiamondStorage storage ds = diamondStorage();
uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
if (selectorPosition == 0) {
addFacet(ds, _facetAddress);
}
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; ) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
if (oldFacetAddress != address(0)) {
revert FunctionAlreadyExists();
}
addFunction(ds, selector, selectorPosition, _facetAddress);
unchecked {
++selectorPosition;
++selectorIndex;
}
}
}
function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
if (_functionSelectors.length == 0) {
revert NoSelectorsInFacet();
}
if (_facetAddress == address(0)) {
revert FacetAddressIsZero();
}
DiamondStorage storage ds = diamondStorage();
uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
if (selectorPosition == 0) {
addFacet(ds, _facetAddress);
}
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; ) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
if (oldFacetAddress == _facetAddress) {
revert FunctionAlreadyExists();
}
removeFunction(ds, oldFacetAddress, selector);
addFunction(ds, selector, selectorPosition, _facetAddress);
unchecked {
++selectorPosition;
++selectorIndex;
}
}
}
function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
if (_functionSelectors.length == 0) {
revert NoSelectorsInFacet();
}
DiamondStorage storage ds = diamondStorage();
if (_facetAddress != address(0)) {
revert FacetAddressIsNotZero();
}
for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; ) {
bytes4 selector = _functionSelectors[selectorIndex];
address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
removeFunction(ds, oldFacetAddress, selector);
unchecked {
++selectorIndex;
}
}
}
function addFacet(DiamondStorage storage ds, address _facetAddress) internal {
enforceHasContractCode(_facetAddress);
ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = ds.facetAddresses.length;
ds.facetAddresses.push(_facetAddress);
}
function addFunction(
DiamondStorage storage ds,
bytes4 _selector,
uint96 _selectorPosition,
address _facetAddress
) internal {
ds.selectorToFacetAndPosition[_selector].functionSelectorPosition = _selectorPosition;
ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(_selector);
ds.selectorToFacetAndPosition[_selector].facetAddress = _facetAddress;
}
function removeFunction(
DiamondStorage storage ds,
address _facetAddress,
bytes4 _selector
) internal {
if (_facetAddress == address(0)) {
revert FunctionDoesNotExist();
}
if (_facetAddress == address(this)) {
revert FunctionIsImmutable();
}
uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition;
uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1;
if (selectorPosition != lastSelectorPosition) {
bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition];
ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector;
ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint96(selectorPosition);
}
ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
delete ds.selectorToFacetAndPosition[_selector];
if (lastSelectorPosition == 0) {
uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
if (facetAddressPosition != lastFacetAddressPosition) {
address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];
ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = facetAddressPosition;
}
ds.facetAddresses.pop();
delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
}
}
function initializeDiamondCut(address _init, bytes memory _calldata) internal {
if (_init == address(0)) {
if (_calldata.length != 0) {
revert InitZeroButCalldataNotEmpty();
}
} else {
if (_calldata.length == 0) {
revert CalldataEmptyButInitNotZero();
}
if (_init != address(this)) {
enforceHasContractCode(_init);
}
(bool success, bytes memory error) = _init.delegatecall(_calldata);
if (!success) {
if (error.length > 0) {
revert(string(error));
} else {
revert InitReverted();
}
}
}
}
function enforceHasContractCode(address _contract) internal view {
uint256 contractSize;
assembly {
contractSize := extcodesize(_contract)
}
if (contractSize == 0) {
revert FacetContainsNoCode();
}
}
}
文件 14 的 20:LibInterchain.sol
pragma solidity 0.8.16;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IUniswapV2.sol";
import "../interfaces/IUniswapV3.sol";
import "../interfaces/IWETH.sol";
import "../interfaces/IRangoStargate.sol";
import "../interfaces/IStargateReceiver.sol";
import "../interfaces/IRangoMessageReceiver.sol";
import "./LibSwapper.sol";
library LibInterchain {
bytes32 internal constant BASE_MESSAGING_CONTRACT_NAMESPACE = hex"ff95014231b901d2b22bd69b4e83dacd84ac05e8c2d1e9fba0c7e2f3ed0db0eb";
struct BaseInterchainStorage {
mapping (address => bool) whitelistMessagingContracts;
}
function addMessagingDApp(address _dapp) internal {
BaseInterchainStorage storage baseStorage = getBaseMessagingContractStorage();
baseStorage.whitelistMessagingContracts[_dapp] = true;
}
function removeMessagingDApp(address _dapp) internal {
BaseInterchainStorage storage baseStorage = getBaseMessagingContractStorage();
require(baseStorage.whitelistMessagingContracts[_dapp], "contract not whitelisted");
delete baseStorage.whitelistMessagingContracts[_dapp];
}
event CrossChainMessageCalled(
address _receiverContract,
address _token,
uint _amount,
IRangoMessageReceiver.ProcessStatus _status,
bytes _appMessage,
bool success,
string failReason
);
event ActionDone(Interchain.ActionType actionType, address contractAddress, bool success, string reason);
event SubActionDone(Interchain.CallSubActionType subActionType, address contractAddress, bool success, string reason);
function encodeIm(Interchain.RangoInterChainMessage memory im) external pure returns (bytes memory) {
return abi.encode(im);
}
function handleDestinationMessage(
address _token,
uint _amount,
Interchain.RangoInterChainMessage memory m
) internal returns (address, uint256 dstAmount, IRango.CrossChainOperationStatus status) {
LibSwapper.BaseSwapperStorage storage baseStorage = LibSwapper.getBaseSwapperStorage();
address sourceToken = m.bridgeRealOutput == LibSwapper.ETH && _token == baseStorage.WETH ? LibSwapper.ETH : _token;
bool ok = true;
address receivedToken = sourceToken;
dstAmount = _amount;
if (m.actionType == Interchain.ActionType.UNI_V2)
(ok, dstAmount, receivedToken) = _handleUniswapV2(sourceToken, _amount, m, baseStorage);
else if (m.actionType == Interchain.ActionType.UNI_V3)
(ok, dstAmount, receivedToken) = _handleUniswapV3(sourceToken, _amount, m, baseStorage);
else if (m.actionType == Interchain.ActionType.CALL)
(ok, dstAmount, receivedToken) = _handleCall(sourceToken, _amount, m, baseStorage);
else if (m.actionType != Interchain.ActionType.NO_ACTION)
revert("Unsupported actionType");
if (ok && m.postAction != Interchain.CallSubActionType.NO_ACTION) {
(ok, dstAmount, receivedToken) = _handlePostAction(receivedToken, dstAmount, m.postAction, baseStorage);
}
status = ok ? IRango.CrossChainOperationStatus.Succeeded : IRango.CrossChainOperationStatus.RefundInDestination;
IRangoMessageReceiver.ProcessStatus dAppStatus = ok
? IRangoMessageReceiver.ProcessStatus.SUCCESS
: IRangoMessageReceiver.ProcessStatus.REFUND_IN_DESTINATION;
_sendTokenWithDApp(receivedToken, dstAmount, m.recipient, m.dAppMessage, m.dAppDestContract, dAppStatus);
return (receivedToken, dstAmount, status);
}
function _handleUniswapV2(
address _token,
uint _amount,
Interchain.RangoInterChainMessage memory _message,
LibSwapper.BaseSwapperStorage storage baseStorage
) private returns (bool ok, uint256 amountOut, address outToken) {
Interchain.UniswapV2Action memory action = abi.decode((_message.action), (Interchain.UniswapV2Action));
if (baseStorage.whitelistContracts[action.dexAddress] != true) {
return (false, _amount, _token);
}
if (action.path.length < 2) {
return (false, _amount, _token);
}
bool shouldDeposit = _token == LibSwapper.ETH && action.path[0] == baseStorage.WETH;
if (!shouldDeposit) {
if (_token != action.path[0]) {
return (false, _amount, _token);
}
} else {
IWETH(baseStorage.WETH).deposit{value : _amount}();
}
LibSwapper.approve(action.path[0], action.dexAddress, _amount);
address toToken = action.path[action.path.length - 1];
uint toBalanceBefore = LibSwapper.getBalanceOf(toToken);
try
IUniswapV2(action.dexAddress).swapExactTokensForTokens(
_amount,
action.amountOutMin,
action.path,
address(this),
action.deadline
)
returns (uint256[] memory) {
emit ActionDone(Interchain.ActionType.UNI_V2, action.dexAddress, true, "");
uint toBalanceAfter = LibSwapper.getBalanceOf(toToken);
SafeERC20.safeApprove(IERC20(action.path[0]), action.dexAddress, 0);
return (true, toBalanceAfter - toBalanceBefore, toToken);
} catch {
emit ActionDone(Interchain.ActionType.UNI_V2, action.dexAddress, true, "Uniswap-V2 call failed");
SafeERC20.safeApprove(IERC20(action.path[0]), action.dexAddress, 0);
return (false, _amount, shouldDeposit ? baseStorage.WETH : _token);
}
}
function _handleUniswapV3(
address _token,
uint _amount,
Interchain.RangoInterChainMessage memory _message,
LibSwapper.BaseSwapperStorage storage baseStorage
) private returns (bool, uint256, address) {
Interchain.UniswapV3ActionExactInputSingleParams memory action = abi
.decode((_message.action), (Interchain.UniswapV3ActionExactInputSingleParams));
if (baseStorage.whitelistContracts[action.dexAddress] != true) {
return (false, _amount, _token);
}
bool shouldDeposit = _token == LibSwapper.ETH && action.tokenIn == baseStorage.WETH;
if (!shouldDeposit) {
if (_token != action.tokenIn) {
return (false, _amount, _token);
}
} else {
IWETH(baseStorage.WETH).deposit{value : _amount}();
}
LibSwapper.approve(action.tokenIn, action.dexAddress, _amount);
uint toBalanceBefore = LibSwapper.getBalanceOf(action.tokenOut);
try
IUniswapV3(action.dexAddress).exactInputSingle(IUniswapV3.ExactInputSingleParams({
tokenIn : action.tokenIn,
tokenOut : action.tokenOut,
fee : action.fee,
recipient : address(this),
deadline : action.deadline,
amountIn : _amount,
amountOutMinimum : action.amountOutMinimum,
sqrtPriceLimitX96 : action.sqrtPriceLimitX96
}))
returns (uint) {
emit ActionDone(Interchain.ActionType.UNI_V3, action.dexAddress, true, "");
uint toBalanceAfter = LibSwapper.getBalanceOf(action.tokenOut);
SafeERC20.safeApprove(IERC20(action.tokenIn), action.dexAddress, 0);
return (true, toBalanceAfter - toBalanceBefore, action.tokenOut);
} catch {
emit ActionDone(Interchain.ActionType.UNI_V3, action.dexAddress, false, "Uniswap-V3 call failed");
SafeERC20.safeApprove(IERC20(action.tokenIn), action.dexAddress, 0);
return (false, _amount, shouldDeposit ? baseStorage.WETH : _token);
}
}
function _handleCall(
address _token,
uint _amount,
Interchain.RangoInterChainMessage memory _message,
LibSwapper.BaseSwapperStorage storage baseStorage
) private returns (bool ok, uint256 amountOut, address outToken) {
Interchain.CallAction memory action = abi.decode((_message.action), (Interchain.CallAction));
if (baseStorage.whitelistContracts[action.target] != true) {
return (false, _amount, _token);
}
if (baseStorage.whitelistContracts[action.spender] != true) {
return (false, _amount, _token);
}
address sourceToken = _token;
if (action.preAction == Interchain.CallSubActionType.WRAP) {
if (_token != LibSwapper.ETH) {
return (false, _amount, _token);
}
if (action.tokenIn != baseStorage.WETH) {
return (false, _amount, _token);
}
(ok, amountOut, sourceToken) = _handleWrap(_token, _amount, baseStorage);
} else if (action.preAction == Interchain.CallSubActionType.UNWRAP) {
if (_token != baseStorage.WETH) {
return (false, _amount, _token);
}
if (action.tokenIn != LibSwapper.ETH) {
return (false, _amount, _token);
}
(ok, amountOut, sourceToken) = _handleUnwrap(_token, _amount, baseStorage);
} else {
ok = true;
if (action.tokenIn != _token) {
return (false, _amount, _token);
}
}
if (!ok)
return (false, _amount, _token);
if (sourceToken != LibSwapper.ETH)
LibSwapper.approve(sourceToken, action.spender, _amount);
uint value = sourceToken == LibSwapper.ETH ? _amount : 0;
uint toBalanceBefore = LibSwapper.getBalanceOf(_message.toToken);
(bool success, bytes memory ret) = action.target.call{value: value}(action.callData);
if (sourceToken != LibSwapper.ETH)
SafeERC20.safeApprove(IERC20(sourceToken), action.spender, 0);
if (success) {
emit ActionDone(Interchain.ActionType.CALL, action.target, true, "");
uint toBalanceAfter = LibSwapper.getBalanceOf(_message.toToken);
return (true, toBalanceAfter - toBalanceBefore, _message.toToken);
} else {
emit ActionDone(Interchain.ActionType.CALL, action.target, false, LibSwapper._getRevertMsg(ret));
return (false, _amount, sourceToken);
}
}
function _handlePostAction(
address _token,
uint _amount,
Interchain.CallSubActionType _postAction,
LibSwapper.BaseSwapperStorage storage baseStorage
) private returns (bool ok, uint256 amountOut, address outToken) {
if (_postAction == Interchain.CallSubActionType.WRAP) {
if (_token != LibSwapper.ETH) {
return (false, _amount, _token);
}
(ok, amountOut, outToken) = _handleWrap(_token, _amount, baseStorage);
} else if (_postAction == Interchain.CallSubActionType.UNWRAP) {
if (_token != baseStorage.WETH) {
return (false, _amount, _token);
}
(ok, amountOut, outToken) = _handleUnwrap(_token, _amount, baseStorage);
} else {
return (false, _amount, _token);
}
if (!ok)
return (false, _amount, _token);
return (ok, amountOut, outToken);
}
function _handleWrap(
address _token,
uint _amount,
LibSwapper.BaseSwapperStorage storage baseStorage
) private returns (bool ok, uint256 amountOut, address outToken) {
if (_token != LibSwapper.ETH) {
return (false, _amount, _token);
}
IWETH(baseStorage.WETH).deposit{value: _amount}();
emit SubActionDone(Interchain.CallSubActionType.WRAP, baseStorage.WETH, true, "");
return (true, _amount, baseStorage.WETH);
}
function _handleUnwrap(
address _token,
uint _amount,
LibSwapper.BaseSwapperStorage storage baseStorage
) private returns (bool ok, uint256 amountOut, address outToken) {
if (_token != baseStorage.WETH)
return (false, _amount, _token);
IWETH(baseStorage.WETH).withdraw(_amount);
emit SubActionDone(Interchain.CallSubActionType.UNWRAP, baseStorage.WETH, true, "");
return (true, _amount, LibSwapper.ETH);
}
function _sendTokenWithDApp(
address _token,
uint256 _amount,
address _receiver,
bytes memory _dAppMessage,
address _dAppReceiverContract,
IRangoMessageReceiver.ProcessStatus processStatus
) internal {
bool thereIsAMessage = _dAppReceiverContract != LibSwapper.ETH;
address immediateReceiver = thereIsAMessage ? _dAppReceiverContract : _receiver;
BaseInterchainStorage storage messagingStorage = getBaseMessagingContractStorage();
emit LibSwapper.SendToken(_token, _amount, immediateReceiver);
if (_token == LibSwapper.ETH) {
LibSwapper._sendNative(immediateReceiver, _amount);
} else {
SafeERC20.safeTransfer(IERC20(_token), immediateReceiver, _amount);
}
if (thereIsAMessage) {
require(
messagingStorage.whitelistMessagingContracts[_dAppReceiverContract],
"3rd-party contract not whitelisted"
);
try IRangoMessageReceiver(_dAppReceiverContract)
.handleRangoMessage(_token, _amount, processStatus, _dAppMessage)
{
emit CrossChainMessageCalled(_dAppReceiverContract, _token, _amount, processStatus, _dAppMessage, true, "");
} catch Error(string memory reason) {
emit CrossChainMessageCalled(_dAppReceiverContract, _token, _amount, processStatus, _dAppMessage, false, reason);
} catch (bytes memory lowLevelData) {
emit CrossChainMessageCalled(_dAppReceiverContract, _token, _amount, processStatus, _dAppMessage, false, LibSwapper._getRevertMsg(lowLevelData));
}
}
}
function getBaseMessagingContractStorage() internal pure returns (BaseInterchainStorage storage s) {
bytes32 namespace = BASE_MESSAGING_CONTRACT_NAMESPACE;
assembly {
s.slot := namespace
}
}
}
文件 15 的 20:LibSwapper.sol
pragma solidity 0.8.16;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IWETH.sol";
import "../interfaces/IRango.sol";
library LibSwapper {
bytes32 internal constant BASE_SWAPPER_NAMESPACE = hex"43da06808a8e54e76a41d6f7b48ddfb23969b1387a8710ef6241423a5aefe64a";
address payable constant ETH = payable(0x0000000000000000000000000000000000000000);
struct BaseSwapperStorage {
address payable feeContractAddress;
address WETH;
mapping(address => bool) whitelistContracts;
mapping(address => mapping(bytes4 => bool)) whitelistMethods;
}
event FeeInfo(
address token,
address indexed affiliatorAddress,
uint platformFee,
uint destinationExecutorFee,
uint affiliateFee,
uint16 indexed dAppTag
);
event CallResult(address target, bool success, bytes returnData);
event RangoSwap(
address indexed requestId,
address fromToken,
address toToken,
uint amountIn,
uint minimumAmountExpected,
uint16 indexed dAppTag,
uint outputAmount,
address receiver
);
event DexOutput(address _token, uint amount);
event SendToken(address _token, uint256 _amount, address _receiver);
event FeeContractAddressUpdated(address _oldAddress, address _newAddress);
event WethContractAddressUpdated(address _oldAddress, address _newAddress);
event Refunded(address _token, uint _amount);
struct Call {
address spender;
address payable target;
address swapFromToken;
address swapToToken;
bool needsTransferFromUser;
uint amount;
bytes callData;
}
struct SwapRequest {
address requestId;
address fromToken;
address toToken;
uint amountIn;
uint platformFee;
uint destinationExecutorFee;
uint affiliateFee;
address payable affiliatorAddress;
uint minimumAmountExpected;
uint16 dAppTag;
}
function setWeth(address _weth) internal {
BaseSwapperStorage storage baseStorage = getBaseSwapperStorage();
address oldAddress = baseStorage.WETH;
baseStorage.WETH = _weth;
require(_weth != address(0), "Invalid WETH!");
emit WethContractAddressUpdated(oldAddress, _weth);
}
function updateFeeContractAddress(address payable _address) internal {
BaseSwapperStorage storage baseSwapperStorage = getBaseSwapperStorage();
address oldAddress = baseSwapperStorage.feeContractAddress;
baseSwapperStorage.feeContractAddress = _address;
emit FeeContractAddressUpdated(oldAddress, _address);
}
function addWhitelist(address contractAddress) internal {
BaseSwapperStorage storage baseStorage = getBaseSwapperStorage();
baseStorage.whitelistContracts[contractAddress] = true;
}
function addMethodWhitelists(address contractAddress, bytes4[] calldata methodIds) internal {
BaseSwapperStorage storage baseStorage = getBaseSwapperStorage();
baseStorage.whitelistContracts[contractAddress] = true;
for (uint i = 0; i < methodIds.length; i++)
baseStorage.whitelistMethods[contractAddress][methodIds[i]] = true;
}
function addMethodWhitelist(address contractAddress, bytes4 methodId) internal {
BaseSwapperStorage storage baseStorage = getBaseSwapperStorage();
baseStorage.whitelistContracts[contractAddress] = true;
baseStorage.whitelistMethods[contractAddress][methodId] = true;
}
function removeWhitelist(address contractAddress) internal {
BaseSwapperStorage storage baseStorage = getBaseSwapperStorage();
delete baseStorage.whitelistContracts[contractAddress];
}
function removeMethodWhitelist(address contractAddress, bytes4 methodId) internal {
BaseSwapperStorage storage baseStorage = getBaseSwapperStorage();
delete baseStorage.whitelistMethods[contractAddress][methodId];
}
function onChainSwapsPreBridge(
SwapRequest memory request,
Call[] calldata calls,
uint extraFee
) internal returns (uint out) {
bool isNative = request.fromToken == ETH;
uint minimumRequiredValue = (isNative ? request.platformFee + request.affiliateFee + request.amountIn + request.destinationExecutorFee : 0) + extraFee;
require(msg.value >= minimumRequiredValue, 'Send more ETH to cover input amount + fee');
(, out) = onChainSwapsInternal(request, calls, extraFee);
emitSwapEvent(request, out, ETH);
return out;
}
function onChainSwapsInternal(
SwapRequest memory request,
Call[] calldata calls,
uint256 extraNativeFee
) internal returns (bytes[] memory, uint) {
uint toBalanceBefore = getBalanceOf(request.toToken);
uint fromBalanceBefore = getBalanceOf(request.fromToken);
uint256[] memory initialBalancesList = getInitialBalancesList(calls);
transferTokensFromUserForSwapRequest(request);
transferTokensFromUserForCalls(calls);
bytes[] memory result = callSwapsAndFees(request, calls);
returnExcessAmounts(request, calls, initialBalancesList);
uint fromBalanceAfter = getBalanceOf(request.fromToken);
if (request.fromToken != ETH) {
require(fromBalanceAfter >= fromBalanceBefore, "Source token balance on contract must not decrease after swap");
if (fromBalanceAfter > fromBalanceBefore)
_sendToken(request.fromToken, fromBalanceAfter - fromBalanceBefore, msg.sender);
}
else {
require(fromBalanceAfter >= fromBalanceBefore - msg.value, "Source token balance on contract must not decrease after swap");
if (fromBalanceAfter > fromBalanceBefore - msg.value + extraNativeFee)
_sendToken(request.fromToken, fromBalanceAfter + msg.value - fromBalanceBefore - extraNativeFee, msg.sender);
}
uint toBalanceAfter = getBalanceOf(request.toToken);
uint secondaryBalance = toBalanceAfter - toBalanceBefore;
require(secondaryBalance >= request.minimumAmountExpected, "Output is less than minimum expected");
return (result, secondaryBalance);
}
function callSwapsAndFees(SwapRequest memory request, Call[] calldata calls) private returns (bytes[] memory) {
bool isSourceNative = request.fromToken == ETH;
BaseSwapperStorage storage baseSwapperStorage = getBaseSwapperStorage();
for (uint256 i = 0; i < calls.length; i++) {
require(baseSwapperStorage.whitelistContracts[calls[i].spender], "Contract spender not whitelisted");
require(baseSwapperStorage.whitelistContracts[calls[i].target], "Contract target not whitelisted");
bytes4 sig = bytes4(calls[i].callData[: 4]);
require(baseSwapperStorage.whitelistMethods[calls[i].target][sig], "Unauthorized call data!");
}
bool hasPlatformFee = request.platformFee > 0;
bool hasDestExecutorFee = request.destinationExecutorFee > 0;
bool hasAffiliateFee = request.affiliateFee > 0;
if (hasPlatformFee || hasDestExecutorFee) {
require(baseSwapperStorage.feeContractAddress != ETH, "Fee contract address not set");
_sendToken(request.fromToken, request.platformFee + request.destinationExecutorFee, baseSwapperStorage.feeContractAddress, isSourceNative, false);
}
if (hasAffiliateFee) {
require(request.affiliatorAddress != ETH, "Invalid affiliatorAddress");
_sendToken(request.fromToken, request.affiliateFee, request.affiliatorAddress, isSourceNative, false);
}
if (hasPlatformFee || hasDestExecutorFee || hasAffiliateFee) {
emit FeeInfo(
request.fromToken,
request.affiliatorAddress,
request.platformFee,
request.destinationExecutorFee,
request.affiliateFee,
request.dAppTag
);
}
bytes[] memory returnData = new bytes[](calls.length);
address tmpSwapFromToken;
for (uint256 i = 0; i < calls.length; i++) {
tmpSwapFromToken = calls[i].swapFromToken;
bool isTokenNative = tmpSwapFromToken == ETH;
if (isTokenNative == false)
approveMax(tmpSwapFromToken, calls[i].spender, calls[i].amount);
(bool success, bytes memory ret) = isTokenNative
? calls[i].target.call{value : calls[i].amount}(calls[i].callData)
: calls[i].target.call(calls[i].callData);
emit CallResult(calls[i].target, success, ret);
if (!success)
revert(_getRevertMsg(ret));
returnData[i] = ret;
}
return returnData;
}
function approve(address token, address spender, uint value) internal {
SafeERC20.safeApprove(IERC20(token), spender, 0);
SafeERC20.safeIncreaseAllowance(IERC20(token), spender, value);
}
function approveMax(address token, address spender, uint value) internal {
uint256 currentAllowance = IERC20(token).allowance(address(this), spender);
if (currentAllowance < value) {
if (currentAllowance != 0) {
SafeERC20.safeApprove(IERC20(token), spender, 0);
}
SafeERC20.safeIncreaseAllowance(IERC20(token), spender, type(uint256).max);
}
}
function _sendToken(address _token, uint256 _amount, address _receiver) internal {
(_token == ETH) ? _sendNative(_receiver, _amount) : SafeERC20.safeTransfer(IERC20(_token), _receiver, _amount);
}
function sumFees(IRango.RangoBridgeRequest memory request) internal pure returns (uint256) {
return request.platformFee + request.affiliateFee + request.destinationExecutorFee;
}
function sumFees(SwapRequest memory request) internal pure returns (uint256) {
return request.platformFee + request.affiliateFee + request.destinationExecutorFee;
}
function collectFees(IRango.RangoBridgeRequest memory request) internal {
bool hasPlatformFee = request.platformFee > 0;
bool hasDestExecutorFee = request.destinationExecutorFee > 0;
bool hasAffiliateFee = request.affiliateFee > 0;
bool hasAnyFee = hasPlatformFee || hasDestExecutorFee || hasAffiliateFee;
if (!hasAnyFee) {
return;
}
bool isSourceNative = request.token == ETH;
BaseSwapperStorage storage baseSwapperStorage = getBaseSwapperStorage();
if (hasPlatformFee || hasDestExecutorFee) {
require(baseSwapperStorage.feeContractAddress != ETH, "Fee contract address not set");
_sendToken(request.token, request.platformFee + request.destinationExecutorFee, baseSwapperStorage.feeContractAddress, isSourceNative, false);
}
if (hasAffiliateFee) {
require(request.affiliatorAddress != ETH, "Invalid affiliatorAddress");
_sendToken(request.token, request.affiliateFee, request.affiliatorAddress, isSourceNative, false);
}
emit FeeInfo(
request.token,
request.affiliatorAddress,
request.platformFee,
request.destinationExecutorFee,
request.affiliateFee,
request.dAppTag
);
}
function collectFeesFromSender(IRango.RangoBridgeRequest memory request) internal {
bool hasPlatformFee = request.platformFee > 0;
bool hasDestExecutorFee = request.destinationExecutorFee > 0;
bool hasAffiliateFee = request.affiliateFee > 0;
bool hasAnyFee = hasPlatformFee || hasDestExecutorFee || hasAffiliateFee;
if (!hasAnyFee) {
return;
}
bool isSourceNative = request.token == ETH;
BaseSwapperStorage storage baseSwapperStorage = getBaseSwapperStorage();
if (hasPlatformFee || hasDestExecutorFee) {
require(baseSwapperStorage.feeContractAddress != ETH, "Fee contract address not set");
if (isSourceNative)
_sendToken(request.token, request.platformFee + request.destinationExecutorFee, baseSwapperStorage.feeContractAddress, isSourceNative, false);
else
SafeERC20.safeTransferFrom(
IERC20(request.token),
msg.sender,
baseSwapperStorage.feeContractAddress,
request.platformFee + request.destinationExecutorFee
);
}
if (hasAffiliateFee) {
require(request.affiliatorAddress != ETH, "Invalid affiliatorAddress");
if (isSourceNative)
_sendToken(request.token, request.affiliateFee, request.affiliatorAddress, isSourceNative, false);
else
SafeERC20.safeTransferFrom(
IERC20(request.token),
msg.sender,
request.affiliatorAddress,
request.affiliateFee
);
}
emit FeeInfo(
request.token,
request.affiliatorAddress,
request.platformFee,
request.destinationExecutorFee,
request.affiliateFee,
request.dAppTag
);
}
function _sendToken(
address _token,
uint256 _amount,
address _receiver,
bool _nativeOut,
bool _withdraw
) internal {
BaseSwapperStorage storage baseStorage = getBaseSwapperStorage();
emit SendToken(_token, _amount, _receiver);
if (_nativeOut) {
if (_withdraw) {
require(_token == baseStorage.WETH, "token mismatch");
IWETH(baseStorage.WETH).withdraw(_amount);
}
_sendNative(_receiver, _amount);
} else {
SafeERC20.safeTransfer(IERC20(_token), _receiver, _amount);
}
}
function _sendNative(address _receiver, uint _amount) internal {
(bool sent,) = _receiver.call{value : _amount}("");
require(sent, "failed to send native");
}
function getBaseSwapperStorage() internal pure returns (BaseSwapperStorage storage s) {
bytes32 namespace = BASE_SWAPPER_NAMESPACE;
assembly {
s.slot := namespace
}
}
function _getRevertMsg(bytes memory _returnData) internal pure returns (string memory) {
if (_returnData.length < 68) return 'Transaction reverted silently';
assembly {
_returnData := add(_returnData, 0x04)
}
return abi.decode(_returnData, (string));
}
function getBalanceOf(address token) internal view returns (uint) {
return token == ETH ? address(this).balance : IERC20(token).balanceOf(address(this));
}
function getInitialBalancesList(Call[] calldata calls) internal view returns (uint256[] memory) {
uint callsLength = calls.length;
uint256[] memory balancesList = new uint256[](callsLength);
address token;
for (uint256 i = 0; i < callsLength; i++) {
token = calls[i].swapToToken;
balancesList[i] = getBalanceOf(token);
if (token == ETH)
balancesList[i] -= msg.value;
}
return balancesList;
}
function transferTokensFromUserForSwapRequest(SwapRequest memory request) private {
uint transferAmount = request.amountIn + sumFees(request);
if (request.fromToken != ETH)
SafeERC20.safeTransferFrom(IERC20(request.fromToken), msg.sender, address(this), transferAmount);
else
require(msg.value >= transferAmount);
}
function transferTokensFromUserForCalls(Call[] calldata calls) private {
uint callsLength = calls.length;
Call calldata call;
address token;
for (uint256 i = 0; i < callsLength; i++) {
call = calls[i];
token = call.swapFromToken;
if (call.needsTransferFromUser && token != ETH)
SafeERC20.safeTransferFrom(IERC20(call.swapFromToken), msg.sender, address(this), call.amount);
}
}
function returnExcessAmounts(
SwapRequest memory request,
Call[] calldata calls,
uint256[] memory initialBalancesList) internal {
uint excessAmountToToken;
address tmpSwapToToken;
uint currentBalanceTo;
for (uint256 i = 0; i < calls.length; i++) {
tmpSwapToToken = calls[i].swapToToken;
currentBalanceTo = getBalanceOf(tmpSwapToToken);
excessAmountToToken = currentBalanceTo - initialBalancesList[i];
if (excessAmountToToken > 0 && tmpSwapToToken != request.toToken) {
_sendToken(tmpSwapToToken, excessAmountToToken, msg.sender);
}
}
}
function emitSwapEvent(SwapRequest memory request, uint output, address receiver) internal {
emit RangoSwap(
request.requestId,
request.fromToken,
request.toToken,
request.amountIn,
request.minimumAmountExpected,
request.dAppTag,
output,
receiver
);
}
}
文件 16 的 20:RangoBaseInterchainMiddleware.sol
pragma solidity 0.8.16;
import "../../libraries/LibDiamond.sol";
import "../../libraries/LibInterchain.sol";
contract RangoBaseInterchainMiddleware {
bytes32 internal constant BASE_MIDDLEWARE_CONTRACT_NAMESPACE = hex"ad914d4300c64e1902ca499875cd8a76ae717047bcfaa9e806ff7ea4f6911268";
struct BaseInterchainMiddlewareStorage {
address rangoDiamond;
address owner;
}
struct whitelistRequest {
address contractAddress;
bytes4[] methodIds;
}
constructor(){updateOwnerInternal(tx.origin);}
function initBaseMiddleware(
address _owner,
address _rangoDiamond,
address _weth
) public onlyOwner {
require(_owner != address(0));
updateOwnerInternal(_owner);
updateRangoDiamondInternal(_rangoDiamond);
LibSwapper.setWeth(_weth);
}
event RangoDiamondAddressUpdated(address oldAddress, address newAddress);
event WethAddressUpdated(address oldAddress, address newAddress);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event Refunded(address _token, uint _amount);
event ContractWhitelisted(address _address);
event ContractAndMethodsWhitelisted(address contractAddress, bytes4[] methods);
event ContractBlacklisted(address _address);
event ContractAndMethodsBlacklisted(address contractAddress, bytes4[] methods);
event MessagingDAppWhitelisted(address _dapp);
event MessagingDAppBlacklisted(address _dapp);
modifier onlyOwner() {
require(msg.sender == getBaseInterchainMiddlewareStorage().owner, "should be called only by owner");
_;
}
modifier onlyDiamond() {
require(msg.sender == getBaseInterchainMiddlewareStorage().rangoDiamond, "should be called only from diamond");
_;
}
receive() external payable {}
function updateRangoDiamondAddress(address newAddress) external onlyOwner {
updateRangoDiamondInternal(newAddress);
}
function updateWethAddress(address newAddress) external onlyOwner {
LibSwapper.setWeth(newAddress);
}
function updateOwner(address newAddress) external onlyOwner {
updateOwnerInternal(newAddress);
}
function refund(address _tokenAddress, uint256 _amount) external onlyOwner {
IERC20 ercToken = IERC20(_tokenAddress);
uint balance = ercToken.balanceOf(address(this));
require(balance >= _amount, 'Insufficient balance');
SafeERC20.safeTransfer(IERC20(_tokenAddress), msg.sender, _amount);
emit Refunded(_tokenAddress, _amount);
}
function refundNative(uint256 _amount) external onlyOwner {
uint balance = address(this).balance;
require(balance >= _amount, 'Insufficient balance');
(bool sent,) = msg.sender.call{value : _amount}("");
require(sent, "failed to send native");
emit Refunded(LibSwapper.ETH, _amount);
}
function addWhitelistContractMiddleWare(whitelistRequest[] calldata req) external onlyOwner {
for (uint i = 0; i < req.length; i++) {
LibSwapper.addMethodWhitelists(req[i].contractAddress, req[i].methodIds);
emit ContractAndMethodsWhitelisted(req[i].contractAddress, req[i].methodIds);
emit ContractWhitelisted(req[i].contractAddress);
}
}
function removeWhitelistMiddleWare(address contractAddress) external onlyOwner {
LibSwapper.removeWhitelist(contractAddress);
emit ContractBlacklisted(contractAddress);
}
function removeContractAndMethodIdsFromWhitelist(
address contractAddress,
bytes4[] calldata methodIds
) external onlyOwner {
LibSwapper.removeWhitelist(contractAddress);
emit ContractBlacklisted(contractAddress);
for (uint i = 0; i < methodIds.length; i++) {
LibSwapper.removeMethodWhitelist(contractAddress, methodIds[i]);
}
if (methodIds.length > 0) {
emit ContractAndMethodsBlacklisted(contractAddress, methodIds);
}
}
function addMessagingDAppsMiddleWare(address[] calldata _dapps) external onlyOwner {
address dapp;
for (uint i = 0; i < _dapps.length; i++) {
dapp = _dapps[i];
LibInterchain.addMessagingDApp(dapp);
emit MessagingDAppWhitelisted(dapp);
}
}
function removeMessagingDAppContractMiddleWare(address _dapp) external onlyOwner {
LibInterchain.removeMessagingDApp(_dapp);
emit MessagingDAppBlacklisted(_dapp);
}
function updateRangoDiamondInternal(address newAddress) private {
BaseInterchainMiddlewareStorage storage s = getBaseInterchainMiddlewareStorage();
address oldAddress = s.rangoDiamond;
s.rangoDiamond = newAddress;
emit RangoDiamondAddressUpdated(oldAddress, newAddress);
}
function updateOwnerInternal(address newAddress) private {
BaseInterchainMiddlewareStorage storage s = getBaseInterchainMiddlewareStorage();
address oldAddress = s.owner;
s.owner = newAddress;
emit OwnershipTransferred(oldAddress, newAddress);
}
function getBaseInterchainMiddlewareStorage() private pure returns (BaseInterchainMiddlewareStorage storage s) {
bytes32 namespace = BASE_MIDDLEWARE_CONTRACT_NAMESPACE;
assembly {
s.slot := namespace
}
}
}
文件 17 的 20:RangoStargateMiddleware.sol
pragma solidity 0.8.16;
import "../../libraries/LibInterchain.sol";
import "../../utils/ReentrancyGuard.sol";
import "../base/RangoBaseInterchainMiddleware.sol";
contract RangoStargateMiddleware is ReentrancyGuard, IRango, IStargateReceiver, RangoBaseInterchainMiddleware {
bytes32 internal constant STARGATE_MIDDLEWARE_NAMESPACE = hex"8f95700cb6d0d3fbe23970b0fed4ae8d3a19af1ff9db49b72f280b34bdf7bad8";
struct RangoStargateMiddlewareStorage {
address stargateRouter;
}
function initStargateMiddleware(
address _owner,
address _stargateRouter,
address _weth
) external onlyOwner {
initBaseMiddleware(_owner, address(0), _weth);
updateStargateRouterAddressInternal(_stargateRouter);
}
event StargateRouterAddressUpdated(address oldAddress, address newAddress);
function updateStargateRouter(address newAddress) external onlyOwner {
updateStargateRouterAddressInternal(newAddress);
}
function sgReceive(
uint16,
bytes memory,
uint256,
address _token,
uint256 amountLD,
bytes memory payload
) external payable override nonReentrant {
require(msg.sender == getRangoStargateMiddlewareStorage().stargateRouter,
"sgReceive function can only be called by Stargate router");
Interchain.RangoInterChainMessage memory m = abi.decode((payload), (Interchain.RangoInterChainMessage));
(address receivedToken, uint dstAmount, IRango.CrossChainOperationStatus status) = LibInterchain.handleDestinationMessage(_token, amountLD, m);
emit RangoBridgeCompleted(
m.requestId,
receivedToken,
m.originalSender,
m.recipient,
dstAmount,
status,
m.dAppTag
);
}
function updateStargateRouterAddressInternal(address newAddress) private {
require(newAddress != address(0), "Invalid StargateRouter");
RangoStargateMiddlewareStorage storage s = getRangoStargateMiddlewareStorage();
address oldAddress = s.stargateRouter;
s.stargateRouter = newAddress;
emit StargateRouterAddressUpdated(oldAddress, newAddress);
}
function getRangoStargateMiddlewareStorage() private pure returns (RangoStargateMiddlewareStorage storage s) {
bytes32 namespace = STARGATE_MIDDLEWARE_NAMESPACE;
assembly {
s.slot := namespace
}
}
}
文件 18 的 20:ReentrancyGuard.sol
pragma solidity 0.8.16;
abstract contract ReentrancyGuard {
bytes32 private constant NAMESPACE = hex"4fe94118b1030ac5f570795d403ee5116fd91b8f0b5d11f2487377c2b0ab2559";
struct ReentrancyStorage {
uint256 status;
}
error ReentrancyError();
uint256 private constant _NOT_ENTERED = 0;
uint256 private constant _ENTERED = 1;
modifier nonReentrant() {
ReentrancyStorage storage s = reentrancyStorage();
if (s.status == _ENTERED) revert ReentrancyError();
s.status = _ENTERED;
_;
s.status = _NOT_ENTERED;
}
function reentrancyStorage() private pure returns (ReentrancyStorage storage data) {
bytes32 position = NAMESPACE;
assembly {
data.slot := position
}
}
}
文件 19 的 20:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 20 的 20:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"contracts/facets/bridges/RangoStargateMiddleware.sol": "RangoStargateMiddleware"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 10000
},
"remappings": []
}
[{"inputs":[],"name":"ReentrancyError","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bytes4[]","name":"methods","type":"bytes4[]"}],"name":"ContractAndMethodsBlacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bytes4[]","name":"methods","type":"bytes4[]"}],"name":"ContractAndMethodsWhitelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_address","type":"address"}],"name":"ContractBlacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_address","type":"address"}],"name":"ContractWhitelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_dapp","type":"address"}],"name":"MessagingDAppBlacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_dapp","type":"address"}],"name":"MessagingDAppWhitelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestId","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"originalSender","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"enum IRango.CrossChainOperationStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"uint16","name":"dAppTag","type":"uint16"}],"name":"RangoBridgeCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requestId","type":"address"},{"indexed":false,"internalType":"address","name":"bridgeToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"bridgeAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"hasInterchainMessage","type":"bool"},{"indexed":false,"internalType":"bool","name":"hasDestinationSwap","type":"bool"},{"indexed":true,"internalType":"uint8","name":"bridgeId","type":"uint8"},{"indexed":true,"internalType":"uint16","name":"dAppTag","type":"uint16"}],"name":"RangoBridgeInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"RangoDiamondAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Refunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"StargateRouterAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"WethAddressUpdated","type":"event"},{"inputs":[{"internalType":"address[]","name":"_dapps","type":"address[]"}],"name":"addMessagingDAppsMiddleWare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes4[]","name":"methodIds","type":"bytes4[]"}],"internalType":"struct RangoBaseInterchainMiddleware.whitelistRequest[]","name":"req","type":"tuple[]"}],"name":"addWhitelistContractMiddleWare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_rangoDiamond","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"name":"initBaseMiddleware","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_stargateRouter","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"name":"initStargateMiddleware","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"refundNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes4[]","name":"methodIds","type":"bytes4[]"}],"name":"removeContractAndMethodIdsFromWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_dapp","type":"address"}],"name":"removeMessagingDAppContractMiddleWare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"removeWhitelistMiddleWare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"sgReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"updateOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"updateRangoDiamondAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"updateStargateRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"updateWethAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]