编译器
0.8.14+commit.80d49f37
文件 1 的 17:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 17:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
set._values[toDeleteIndex] = lastValue;
set._indexes[lastValue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 3 的 17:ICommonOFT.sol
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
interface ICommonOFT is IERC165 {
struct LzCallParams {
address payable refundAddress;
address zroPaymentAddress;
bytes adapterParams;
}
function estimateSendFee(uint16 _dstChainId, bytes32 _toAddress, uint _amount, bool _useZro, bytes calldata _adapterParams) external view returns (uint nativeFee, uint zroFee);
function estimateSendAndCallFee(uint16 _dstChainId, bytes32 _toAddress, uint _amount, bytes calldata _payload, uint64 _dstGasForCall, bool _useZro, bytes calldata _adapterParams) external view returns (uint nativeFee, uint zroFee);
function circulatingSupply() external view returns (uint);
function token() external view returns (address);
}
文件 4 的 17:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 5 的 17: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);
}
文件 6 的 17:ILzApp.sol
pragma solidity ^0.8.0;
interface ILzApp {
function minDstGasLookup(uint16 _dstChainId, uint16 _type) external view returns (uint256 _minGasLimit);
}
文件 7 的 17:IOFTWithFee.sol
pragma solidity >=0.5.0;
import "../ICommonOFT.sol";
interface IOFTWithFee is ICommonOFT {
function sendFrom(address _from, uint16 _dstChainId, bytes32 _toAddress, uint _amount, uint _minAmount, LzCallParams calldata _callParams) external payable;
function sendAndCall(address _from, uint16 _dstChainId, bytes32 _toAddress, uint _amount, uint _minAmount, bytes calldata _payload, uint64 _dstGasForCall, LzCallParams calldata _callParams) external payable;
}
文件 8 的 17:IStargateEthVault.sol
pragma solidity ^0.8.0;
interface IStargateEthVault {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function withdraw(uint256) external;
function approve(address guy, uint256 wad) external returns (bool);
function transferFrom(
address src,
address dst,
uint256 wad
) external returns (bool);
}
文件 9 的 17:IStargateRouter.sol
pragma solidity ^0.8.0;
interface IStargateRouter {
struct lzTxObj {
uint256 dstGasForCall;
uint256 dstNativeAmount;
bytes dstNativeAddr;
}
function addLiquidity(
uint256 _poolId,
uint256 _amountLD,
address _to
) external;
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 redeemRemote(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
uint256 _minAmountLD,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external payable;
function instantRedeemLocal(
uint16 _srcPoolId,
uint256 _amountLP,
address _to
) external returns (uint256);
function redeemLocal(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external payable;
function sendCredits(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress
) external payable;
function quoteLayerZeroFee(
uint16 _dstChainId,
uint8 _functionType,
bytes calldata _toAddress,
bytes calldata _transferAndCallPayload,
lzTxObj memory _lzTxParams
) external view returns (uint256, uint256);
}
文件 10 的 17:IWETH.sol
pragma solidity ^0.8.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint256 value) external returns (bool);
function withdraw(uint256) external;
}
文件 11 的 17:IWooCrossChainRouterV2.sol
pragma solidity =0.8.14;
interface IWooCrossChainRouterV2 {
struct SrcInfos {
address fromToken;
address bridgeToken;
uint256 fromAmount;
uint256 minBridgeAmount;
}
struct DstInfos {
uint16 chainId;
address toToken;
address bridgeToken;
uint256 minToAmount;
uint256 airdropNativeAmount;
}
event WooCrossSwapOnSrcChain(
uint256 indexed refId,
address indexed sender,
address indexed to,
address fromToken,
uint256 fromAmount,
uint256 minBridgeAmount,
uint256 realBridgeAmount
);
event WooCrossSwapOnDstChain(
uint256 indexed refId,
address indexed sender,
address indexed to,
address bridgedToken,
uint256 bridgedAmount,
address toToken,
address realToToken,
uint256 minToAmount,
uint256 realToAmount
);
function weth() external view returns (address);
function bridgeSlippage() external view returns (uint256);
function dstGasForSwapCall() external view returns (uint256);
function dstGasForNoSwapCall() external view returns (uint256);
function sgChainIdLocal() external view returns (uint16);
function wooCrossChainRouters(uint16 chainId) external view returns (address wooCrossChainRouter);
function sgETHs(uint16 chainId) external view returns (address sgETH);
function sgPoolIds(uint16 chainId, address token) external view returns (uint256 poolId);
function crossSwap(
uint256 refId,
address payable to,
SrcInfos memory srcInfos,
DstInfos memory dstInfos
) external payable;
function sgReceive(
uint16 srcChainId,
bytes memory srcAddress,
uint256 nonce,
address bridgedToken,
uint256 amountLD,
bytes memory payload
) external;
function quoteLayerZeroFee(
uint256 refId,
address to,
SrcInfos memory srcInfos,
DstInfos memory dstInfos
) external view returns (uint256 nativeAmount, uint256 zroAmount);
function allDirectBridgeTokens() external view returns (address[] memory tokens);
function allDirectBridgeTokensLength() external view returns (uint256 length);
}
文件 12 的 17:IWooPPV2.sol
pragma solidity =0.8.14;
interface IWooPPV2 {
event Deposit(address indexed token, address indexed sender, uint256 amount);
event Withdraw(address indexed token, address indexed receiver, uint256 amount);
event Migrate(address indexed token, address indexed receiver, uint256 amount);
event AdminUpdated(address indexed addr, bool flag);
event FeeAddrUpdated(address indexed newFeeAddr);
event WooracleUpdated(address indexed newWooracle);
event WooSwap(
address indexed fromToken,
address indexed toToken,
uint256 fromAmount,
uint256 toAmount,
address from,
address indexed to,
address rebateTo,
uint256 swapVol,
uint256 swapFee
);
function quoteToken() external view returns (address);
function poolSize(address token) external view returns (uint256);
function tryQuery(
address fromToken,
address toToken,
uint256 fromAmount
) external view returns (uint256 toAmount);
function query(
address fromToken,
address toToken,
uint256 fromAmount
) external view returns (uint256 toAmount);
function swap(
address fromToken,
address toToken,
uint256 fromAmount,
uint256 minToAmount,
address to,
address rebateTo
) external returns (uint256 realToAmount);
function deposit(address token, uint256 amount) external;
}
文件 13 的 17:IWooRouterV2.sol
pragma solidity =0.8.14;
import "../interfaces/IWooPPV2.sol";
interface IWooRouterV2 {
enum SwapType {
WooSwap,
DodoSwap
}
event WooRouterSwap(
SwapType swapType,
address indexed fromToken,
address indexed toToken,
uint256 fromAmount,
uint256 toAmount,
address from,
address indexed to,
address rebateTo
);
event WooPoolChanged(address newPool);
function WETH() external view returns (address);
function wooPool() external view returns (IWooPPV2);
function querySwap(
address fromToken,
address toToken,
uint256 fromAmount
) external view returns (uint256 toAmount);
function tryQuerySwap(
address fromToken,
address toToken,
uint256 fromAmount
) external view returns (uint256 toAmount);
function swap(
address fromToken,
address toToken,
uint256 fromAmount,
uint256 minToAmount,
address payable to,
address rebateTo
) external payable returns (uint256 realToAmount);
function externalSwap(
address approveTarget,
address swapTarget,
address fromToken,
address toToken,
uint256 fromAmount,
uint256 minToAmount,
address payable to,
bytes calldata data
) external payable returns (uint256 realToAmount);
}
文件 14 的 17:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 15 的 17:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 16 的 17:TransferHelper.sol
pragma solidity ^0.8.0;
library TransferHelper {
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeApprove: approve failed"
);
}
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeTransfer: transfer failed"
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::transferFrom: transferFrom failed"
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "TransferHelper::safeTransferETH: ETH transfer failed");
}
}
文件 17 的 17:WooCrossChainRouterV2.sol
pragma solidity =0.8.14;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {ICommonOFT, IOFTWithFee} from "@layerzerolabs/solidity-examples/contracts/token/oft/v2/fee/IOFTWithFee.sol";
import {IWETH} from "./interfaces/IWETH.sol";
import {IWooCrossChainRouterV2} from "./interfaces/IWooCrossChainRouterV2.sol";
import {IWooRouterV2} from "./interfaces/IWooRouterV2.sol";
import {IStargateEthVault} from "./interfaces/Stargate/IStargateEthVault.sol";
import {IStargateRouter} from "./interfaces/Stargate/IStargateRouter.sol";
import {ILzApp} from "./interfaces/LayerZero/ILzApp.sol";
import {TransferHelper} from "./libraries/TransferHelper.sol";
contract WooCrossChainRouterV2 is IWooCrossChainRouterV2, Ownable, ReentrancyGuard {
using EnumerableSet for EnumerableSet.AddressSet;
address public constant ETH_PLACEHOLDER_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
IWooRouterV2 public wooRouter;
IStargateRouter public stargateRouter;
address public immutable weth;
uint256 public bridgeSlippage;
uint256 public dstGasForSwapCall;
uint256 public dstGasForNoSwapCall;
uint16 public sgChainIdLocal;
mapping(uint16 => address) public wooCrossChainRouters;
mapping(uint16 => address) public sgETHs;
mapping(uint16 => mapping(address => uint256)) public sgPoolIds;
mapping(address => address) public tokenToOFTs;
EnumerableSet.AddressSet private directBridgeTokens;
receive() external payable {}
constructor(
address _weth,
address _wooRouter,
address _stargateRouter,
uint16 _sgChainIdLocal
) {
wooRouter = IWooRouterV2(_wooRouter);
stargateRouter = IStargateRouter(_stargateRouter);
weth = _weth;
bridgeSlippage = 100;
dstGasForSwapCall = 360000;
dstGasForNoSwapCall = 80000;
sgChainIdLocal = _sgChainIdLocal;
_initSgETHs();
_initSgPoolIds();
_initTokenToOFTs(_sgChainIdLocal);
}
function crossSwap(
uint256 refId,
address payable to,
SrcInfos memory srcInfos,
DstInfos memory dstInfos
) external payable nonReentrant {
require(srcInfos.fromToken != address(0), "WooCrossChainRouterV2: !srcInfos.fromToken");
require(
dstInfos.toToken != address(0) && dstInfos.toToken != sgETHs[dstInfos.chainId],
"WooCrossChainRouterV2: !dstInfos.toToken"
);
require(to != address(0), "WooCrossChainRouterV2: !to");
uint256 msgValue = msg.value;
uint256 bridgeAmount;
{
if (srcInfos.fromToken == ETH_PLACEHOLDER_ADDR) {
require(srcInfos.fromAmount <= msgValue, "WooCrossChainRouterV2: !srcInfos.fromAmount");
srcInfos.fromToken = weth;
IWETH(weth).deposit{value: srcInfos.fromAmount}();
msgValue -= srcInfos.fromAmount;
} else {
TransferHelper.safeTransferFrom(srcInfos.fromToken, msg.sender, address(this), srcInfos.fromAmount);
}
if (!directBridgeTokens.contains(srcInfos.fromToken) && srcInfos.fromToken != srcInfos.bridgeToken) {
TransferHelper.safeApprove(srcInfos.fromToken, address(wooRouter), srcInfos.fromAmount);
bridgeAmount = wooRouter.swap(
srcInfos.fromToken,
srcInfos.bridgeToken,
srcInfos.fromAmount,
srcInfos.minBridgeAmount,
payable(address(this)),
to
);
} else {
require(
srcInfos.fromAmount == srcInfos.minBridgeAmount,
"WooCrossChainRouterV2: !srcInfos.minBridgeAmount"
);
bridgeAmount = srcInfos.fromAmount;
}
require(
bridgeAmount <= IERC20(srcInfos.bridgeToken).balanceOf(address(this)),
"WooCrossChainRouterV2: !bridgeAmount"
);
}
address oft = tokenToOFTs[srcInfos.bridgeToken];
if (oft != address(0)) {
_bridgeByOFT(refId, to, msgValue, bridgeAmount, IOFTWithFee(oft), srcInfos, dstInfos);
} else {
_bridgeByStargate(refId, to, msgValue, bridgeAmount, srcInfos, dstInfos);
}
emit WooCrossSwapOnSrcChain(
refId,
_msgSender(),
to,
srcInfos.fromToken,
srcInfos.fromAmount,
srcInfos.minBridgeAmount,
bridgeAmount
);
}
function onOFTReceived(
uint16 srcChainId,
bytes memory,
uint64,
bytes32 from,
uint256 amountLD,
bytes memory payload
) external {
require(_isLegitOFT(_msgSender()), "WooCrossChainRouterV2: INVALID_CALLER");
require(
wooCrossChainRouters[srcChainId] == address(uint160(uint256(from))),
"WooCrossChainRouterV2: INVALID_FROM"
);
address bridgedToken = IOFTWithFee(_msgSender()).token();
(uint256 refId, address to, address toToken, uint256 minToAmount) = abi.decode(
payload,
(uint256, address, address, uint256)
);
_handleERC20Received(refId, to, toToken, bridgedToken, amountLD, minToAmount);
}
function sgReceive(
uint16,
bytes memory,
uint256,
address bridgedToken,
uint256 amountLD,
bytes memory payload
) external {
require(msg.sender == address(stargateRouter), "WooCrossChainRouterV2: INVALID_CALLER");
(uint256 refId, address to, address toToken, uint256 minToAmount) = abi.decode(
payload,
(uint256, address, address, uint256)
);
if (bridgedToken == sgETHs[sgChainIdLocal]) {
_handleNativeReceived(refId, to, toToken, amountLD, minToAmount);
} else {
_handleERC20Received(refId, to, toToken, bridgedToken, amountLD, minToAmount);
}
}
function quoteLayerZeroFee(
uint256 refId,
address to,
SrcInfos memory srcInfos,
DstInfos memory dstInfos
) external view returns (uint256, uint256) {
bytes memory payload = abi.encode(refId, to, dstInfos.toToken, dstInfos.minToAmount);
address oft = tokenToOFTs[srcInfos.bridgeToken];
if (oft != address(0)) {
uint256 dstGasForCall = _getDstGasForCall(dstInfos);
bytes memory adapterParams = _getAdapterParams(to, oft, dstGasForCall, dstInfos);
bool useZro = false;
bytes32 dstWooCrossChainRouter = bytes32(uint256(uint160(wooCrossChainRouters[dstInfos.chainId])));
return
IOFTWithFee(oft).estimateSendAndCallFee(
dstInfos.chainId,
dstWooCrossChainRouter,
srcInfos.minBridgeAmount,
payload,
uint64(dstGasForCall),
useZro,
adapterParams
);
} else {
IStargateRouter.lzTxObj memory obj = _getLzTxObj(to, dstInfos);
return
stargateRouter.quoteLayerZeroFee(
dstInfos.chainId,
1,
obj.dstNativeAddr,
payload,
obj
);
}
}
function allDirectBridgeTokens() external view returns (address[] memory) {
uint256 length = directBridgeTokens.length();
address[] memory tokens = new address[](length);
unchecked {
for (uint256 i = 0; i < length; ++i) {
tokens[i] = directBridgeTokens.at(i);
}
}
return tokens;
}
function allDirectBridgeTokensLength() external view returns (uint256) {
return directBridgeTokens.length();
}
function _initSgETHs() internal {
sgETHs[101] = 0x72E2F4830b9E45d52F80aC08CB2bEC0FeF72eD9c;
sgETHs[110] = 0x82CbeCF39bEe528B5476FE6d1550af59a9dB6Fc0;
sgETHs[111] = 0xb69c8CBCD90A39D8D3d3ccf0a3E968511C3856A0;
}
function _initSgPoolIds() internal {
sgPoolIds[101][0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48] = 1;
sgPoolIds[101][0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2] = 13;
sgPoolIds[101][0x4691937a7508860F876c9c0a2a617E7d9E945D4B] = 20;
sgPoolIds[102][0x55d398326f99059fF775485246999027B3197955] = 2;
sgPoolIds[102][0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56] = 5;
sgPoolIds[102][0x4691937a7508860F876c9c0a2a617E7d9E945D4B] = 20;
sgPoolIds[106][0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E] = 1;
sgPoolIds[106][0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7] = 2;
sgPoolIds[106][0xaBC9547B534519fF73921b1FBA6E672b5f58D083] = 20;
sgPoolIds[109][0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174] = 1;
sgPoolIds[109][0xc2132D05D31c914a87C6611C10748AEb04B58e8F] = 2;
sgPoolIds[109][0x1B815d120B3eF02039Ee11dC2d33DE7aA4a8C603] = 20;
sgPoolIds[110][0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8] = 1;
sgPoolIds[110][0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9] = 2;
sgPoolIds[110][0x82aF49447D8a07e3bd95BD0d56f35241523fBab1] = 13;
sgPoolIds[110][0xcAFcD85D8ca7Ad1e1C6F82F651fA15E33AEfD07b] = 20;
sgPoolIds[111][0x7F5c764cBc14f9669B88837ca1490cCa17c31607] = 1;
sgPoolIds[111][0x4200000000000000000000000000000000000006] = 13;
sgPoolIds[111][0x871f2F2ff935FD1eD867842FF2a7bfD051A5E527] = 20;
sgPoolIds[112][0x04068DA6C83AFCFA0e13ba15A6696662335D5B75] = 1;
sgPoolIds[112][0x6626c47c00F1D87902fc13EECfaC3ed06D5E8D8a] = 20;
}
function _initTokenToOFTs(uint16 _sgChainIdLocal) internal {
address btcbOFT = 0x2297aEbD383787A160DD0d9F71508148769342E3;
if (_sgChainIdLocal == 106) {
tokenToOFTs[0x152b9d0FdC40C096757F570A51E494bd4b943E50] = btcbOFT;
}
tokenToOFTs[btcbOFT] = btcbOFT;
}
function _getDstGasForCall(DstInfos memory dstInfos) internal view returns (uint256) {
return (dstInfos.toToken == dstInfos.bridgeToken) ? dstGasForNoSwapCall : dstGasForSwapCall;
}
function _getAdapterParams(
address to,
address oft,
uint256 dstGasForCall,
DstInfos memory dstInfos
) internal view returns (bytes memory) {
uint256 providedGasLimit = ILzApp(oft).minDstGasLookup(dstInfos.chainId, 1) + dstGasForCall;
return
abi.encodePacked(
uint16(2),
providedGasLimit,
dstInfos.airdropNativeAmount,
to
);
}
function _getLzTxObj(address to, DstInfos memory dstInfos) internal view returns (IStargateRouter.lzTxObj memory) {
uint256 dstGasForCall = _getDstGasForCall(dstInfos);
return IStargateRouter.lzTxObj(dstGasForCall, dstInfos.airdropNativeAmount, abi.encodePacked(to));
}
function _isLegitOFT(address caller) internal view returns (bool) {
return tokenToOFTs[caller] != address(0);
}
function _bridgeByOFT(
uint256 refId,
address payable to,
uint256 msgValue,
uint256 bridgeAmount,
IOFTWithFee oft,
SrcInfos memory srcInfos,
DstInfos memory dstInfos
) internal {
{
address token = oft.token();
require(token == srcInfos.bridgeToken, "WooCrossChainRouterV2: !token");
if (token != address(oft)) {
TransferHelper.safeApprove(srcInfos.bridgeToken, address(oft), bridgeAmount);
}
}
uint256 minAmount = (bridgeAmount * (10000 - bridgeSlippage)) / 10000;
bytes memory payload = abi.encode(refId, to, dstInfos.toToken, dstInfos.minToAmount);
uint256 dstGasForCall = _getDstGasForCall(dstInfos);
ICommonOFT.LzCallParams memory callParams;
{
bytes memory adapterParams = _getAdapterParams(to, address(oft), dstGasForCall, dstInfos);
callParams = ICommonOFT.LzCallParams(
payable(msg.sender),
address(0),
adapterParams
);
}
bytes32 dstWooCrossChainRouter = bytes32(uint256(uint160(wooCrossChainRouters[dstInfos.chainId])));
oft.sendAndCall{value: msgValue}(
address(this),
dstInfos.chainId,
dstWooCrossChainRouter,
bridgeAmount,
minAmount,
payload,
uint64(dstGasForCall),
callParams
);
}
function _bridgeByStargate(
uint256 refId,
address payable to,
uint256 msgValue,
uint256 bridgeAmount,
SrcInfos memory srcInfos,
DstInfos memory dstInfos
) internal {
uint256 srcPoolId = sgPoolIds[sgChainIdLocal][srcInfos.bridgeToken];
require(srcPoolId > 0, "WooCrossChainRouterV2: !srcInfos.bridgeToken");
uint256 dstPoolId = sgPoolIds[dstInfos.chainId][dstInfos.bridgeToken];
require(dstPoolId > 0, "WooCrossChainRouterV2: !dstInfos.bridgeToken");
bytes memory payload = abi.encode(refId, to, dstInfos.toToken, dstInfos.minToAmount);
uint256 dstMinBridgeAmount = (bridgeAmount * (10000 - bridgeSlippage)) / 10000;
bytes memory dstWooCrossChainRouter = abi.encodePacked(wooCrossChainRouters[dstInfos.chainId]);
IStargateRouter.lzTxObj memory obj = _getLzTxObj(to, dstInfos);
if (srcInfos.bridgeToken == weth) {
IWETH(weth).withdraw(bridgeAmount);
address sgETH = sgETHs[sgChainIdLocal];
IStargateEthVault(sgETH).deposit{value: bridgeAmount}();
TransferHelper.safeApprove(sgETH, address(stargateRouter), bridgeAmount);
} else {
TransferHelper.safeApprove(srcInfos.bridgeToken, address(stargateRouter), bridgeAmount);
}
stargateRouter.swap{value: msgValue}(
dstInfos.chainId,
srcPoolId,
dstPoolId,
payable(_msgSender()),
bridgeAmount,
dstMinBridgeAmount,
obj,
dstWooCrossChainRouter,
payload
);
}
function _handleNativeReceived(
uint256 refId,
address to,
address toToken,
uint256 bridgedAmount,
uint256 minToAmount
) internal {
address msgSender = _msgSender();
if (toToken == ETH_PLACEHOLDER_ADDR) {
TransferHelper.safeTransferETH(to, bridgedAmount);
emit WooCrossSwapOnDstChain(
refId,
msgSender,
to,
weth,
bridgedAmount,
toToken,
ETH_PLACEHOLDER_ADDR,
minToAmount,
bridgedAmount
);
} else {
try
wooRouter.swap{value: bridgedAmount}(
ETH_PLACEHOLDER_ADDR,
toToken,
bridgedAmount,
minToAmount,
payable(to),
to
)
returns (uint256 realToAmount) {
emit WooCrossSwapOnDstChain(
refId,
msgSender,
to,
weth,
bridgedAmount,
toToken,
toToken,
minToAmount,
realToAmount
);
} catch {
TransferHelper.safeTransferETH(to, bridgedAmount);
emit WooCrossSwapOnDstChain(
refId,
msgSender,
to,
weth,
bridgedAmount,
toToken,
ETH_PLACEHOLDER_ADDR,
minToAmount,
bridgedAmount
);
}
}
}
function _handleERC20Received(
uint256 refId,
address to,
address toToken,
address bridgedToken,
uint256 bridgedAmount,
uint256 minToAmount
) internal {
address msgSender = _msgSender();
if (toToken == bridgedToken) {
TransferHelper.safeTransfer(bridgedToken, to, bridgedAmount);
emit WooCrossSwapOnDstChain(
refId,
msgSender,
to,
bridgedToken,
bridgedAmount,
toToken,
toToken,
minToAmount,
bridgedAmount
);
} else {
TransferHelper.safeApprove(bridgedToken, address(wooRouter), bridgedAmount);
try wooRouter.swap(bridgedToken, toToken, bridgedAmount, minToAmount, payable(to), to) returns (
uint256 realToAmount
) {
emit WooCrossSwapOnDstChain(
refId,
msgSender,
to,
bridgedToken,
bridgedAmount,
toToken,
toToken,
minToAmount,
realToAmount
);
} catch {
TransferHelper.safeTransfer(bridgedToken, to, bridgedAmount);
emit WooCrossSwapOnDstChain(
refId,
msgSender,
to,
bridgedToken,
bridgedAmount,
toToken,
bridgedToken,
minToAmount,
bridgedAmount
);
}
}
}
function setWooRouter(address _wooRouter) external onlyOwner {
require(_wooRouter != address(0), "WooCrossChainRouterV2: !_wooRouter");
wooRouter = IWooRouterV2(_wooRouter);
}
function setStargateRouter(address _stargateRouter) external onlyOwner {
require(_stargateRouter != address(0), "WooCrossChainRouterV2: !_stargateRouter");
stargateRouter = IStargateRouter(_stargateRouter);
}
function setBridgeSlippage(uint256 _bridgeSlippage) external onlyOwner {
require(_bridgeSlippage <= 10000, "WooCrossChainRouterV2: !_bridgeSlippage");
bridgeSlippage = _bridgeSlippage;
}
function setDstGasForSwapCall(uint256 _dstGasForSwapCall) external onlyOwner {
dstGasForSwapCall = _dstGasForSwapCall;
}
function setDstGasForNoSwapCall(uint256 _dstGasForNoSwapCall) external onlyOwner {
dstGasForNoSwapCall = _dstGasForNoSwapCall;
}
function setSgChainIdLocal(uint16 _sgChainIdLocal) external onlyOwner {
sgChainIdLocal = _sgChainIdLocal;
}
function setWooCrossChainRouter(uint16 chainId, address wooCrossChainRouter) external onlyOwner {
require(wooCrossChainRouter != address(0), "WooCrossChainRouterV2: !wooCrossChainRouter");
wooCrossChainRouters[chainId] = wooCrossChainRouter;
}
function setSgETH(uint16 chainId, address token) external onlyOwner {
require(token != address(0), "WooCrossChainRouterV2: !token");
sgETHs[chainId] = token;
}
function setSgPoolId(
uint16 chainId,
address token,
uint256 poolId
) external onlyOwner {
sgPoolIds[chainId][token] = poolId;
}
function setTokenToOFT(address token, address oft) external onlyOwner {
tokenToOFTs[token] = oft;
}
function addDirectBridgeToken(address token) external onlyOwner {
bool success = directBridgeTokens.add(token);
require(success, "WooCrossChainRouterV2: token exist");
}
function removeDirectBridgeToken(address token) external onlyOwner {
bool success = directBridgeTokens.remove(token);
require(success, "WooCrossChainRouterV2: token not exist");
}
function inCaseTokenGotStuck(address stuckToken) external onlyOwner {
if (stuckToken == ETH_PLACEHOLDER_ADDR) {
TransferHelper.safeTransferETH(msg.sender, address(this).balance);
} else {
uint256 amount = IERC20(stuckToken).balanceOf(address(this));
TransferHelper.safeTransfer(stuckToken, msg.sender, amount);
}
}
}
{
"compilationTarget": {
"contracts/WooCrossChainRouterV2.sol": "WooCrossChainRouterV2"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 20000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_wooRouter","type":"address"},{"internalType":"address","name":"_stargateRouter","type":"address"},{"internalType":"uint16","name":"_sgChainIdLocal","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"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":"uint256","name":"refId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"bridgedToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"bridgedAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"toToken","type":"address"},{"indexed":false,"internalType":"address","name":"realToToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"minToAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"realToAmount","type":"uint256"}],"name":"WooCrossSwapOnDstChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"refId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"fromToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minBridgeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"realBridgeAmount","type":"uint256"}],"name":"WooCrossSwapOnSrcChain","type":"event"},{"inputs":[],"name":"ETH_PLACEHOLDER_ADDR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"addDirectBridgeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allDirectBridgeTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allDirectBridgeTokensLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridgeSlippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"refId","type":"uint256"},{"internalType":"address payable","name":"to","type":"address"},{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"bridgeToken","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"minBridgeAmount","type":"uint256"}],"internalType":"struct IWooCrossChainRouterV2.SrcInfos","name":"srcInfos","type":"tuple"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"address","name":"bridgeToken","type":"address"},{"internalType":"uint256","name":"minToAmount","type":"uint256"},{"internalType":"uint256","name":"airdropNativeAmount","type":"uint256"}],"internalType":"struct IWooCrossChainRouterV2.DstInfos","name":"dstInfos","type":"tuple"}],"name":"crossSwap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"dstGasForNoSwapCall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dstGasForSwapCall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stuckToken","type":"address"}],"name":"inCaseTokenGotStuck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes32","name":"from","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"onOFTReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"refId","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"bridgeToken","type":"address"},{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"minBridgeAmount","type":"uint256"}],"internalType":"struct IWooCrossChainRouterV2.SrcInfos","name":"srcInfos","type":"tuple"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"address","name":"bridgeToken","type":"address"},{"internalType":"uint256","name":"minToAmount","type":"uint256"},{"internalType":"uint256","name":"airdropNativeAmount","type":"uint256"}],"internalType":"struct IWooCrossChainRouterV2.DstInfos","name":"dstInfos","type":"tuple"}],"name":"quoteLayerZeroFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"removeDirectBridgeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bridgeSlippage","type":"uint256"}],"name":"setBridgeSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dstGasForNoSwapCall","type":"uint256"}],"name":"setDstGasForNoSwapCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dstGasForSwapCall","type":"uint256"}],"name":"setDstGasForSwapCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_sgChainIdLocal","type":"uint16"}],"name":"setSgChainIdLocal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"token","type":"address"}],"name":"setSgETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"poolId","type":"uint256"}],"name":"setSgPoolId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stargateRouter","type":"address"}],"name":"setStargateRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"oft","type":"address"}],"name":"setTokenToOFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"wooCrossChainRouter","type":"address"}],"name":"setWooCrossChainRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wooRouter","type":"address"}],"name":"setWooRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sgChainIdLocal","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"sgETHs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"address","name":"","type":"address"}],"name":"sgPoolIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"bridgedToken","type":"address"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"sgReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stargateRouter","outputs":[{"internalType":"contract IStargateRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenToOFTs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"wooCrossChainRouters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wooRouter","outputs":[{"internalType":"contract IWooRouterV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]