文件 1 的 13:Address.sol
pragma solidity ^0.7.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 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) private 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 的 13:BytesLib.sol
pragma solidity >=0.7.0 <0.8.0;
import "@openzeppelin/contracts/math/SafeMath.sol";
library BytesLib {
using SafeMath for uint256;
function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
require(_length.add(31) >= _length, "slice_overflow");
require(_bytes.length >= _start.add(_length), "slice_outOfBounds");
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
tempBytes := mload(0x40)
let lengthmod := and(_length, 31)
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
mstore(0x40, and(add(mc, 31), not(31)))
}
default {
tempBytes := mload(0x40)
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
require(_bytes.length >= _start.add(2), "toUint16_outOfBounds");
uint16 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x2), _start))
}
return tempUint;
}
function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
require(_bytes.length >= _start.add(32), "toBytes32_outOfBounds");
bytes32 tempBytes32;
assembly {
tempBytes32 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes32;
}
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_bytes.length >= _start.add(20), "toAddress_outOfBounds");
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
}
文件 3 的 13:Context.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 4 的 13:IERC20.sol
pragma solidity ^0.7.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, 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 sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 5 的 13:IStargateEthVault.sol
pragma solidity 0.7.6;
interface IStargateEthVault {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint) external;
function approve(address guy, uint wad) external returns (bool);
function transferFrom(
address src,
address dst,
uint wad
) external returns (bool);
}
文件 6 的 13:IStargateReceiver.sol
pragma solidity 0.7.6;
interface IStargateReceiver {
function sgReceive(
uint16 _chainId,
bytes memory _srcAddress,
uint256 _nonce,
address _token,
uint256 amountLD,
bytes memory payload
) external;
}
文件 7 的 13:IStargateRouter.sol
pragma solidity >=0.7.6 <=0.8.4;
pragma abicoder v2;
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);
}
文件 8 的 13:Ownable.sol
pragma solidity ^0.7.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 9 的 13:ReentrancyGuard.sol
pragma solidity ^0.7.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;
}
}
文件 10 的 13:SafeCall.sol
pragma solidity 0.7.6;
library SafeCall {
function safeCall(
address _target,
uint256 _gas,
uint256 _value,
uint16 _maxCopy,
bytes memory _calldata
) internal returns (bool, bytes memory) {
uint256 _toCopy;
bool _success;
bytes memory _returnData = new bytes(_maxCopy);
assembly {
_success := call(
_gas,
_target,
_value,
add(_calldata, 0x20),
mload(_calldata),
0,
0
)
_toCopy := returndatasize()
if gt(_toCopy, _maxCopy) {
_toCopy := _maxCopy
}
mstore(_returnData, _toCopy)
returndatacopy(add(_returnData, 0x20), 0, _toCopy)
}
return (_success, _returnData);
}
}
文件 11 的 13:SafeERC20.sol
pragma solidity ^0.7.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
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).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
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");
}
}
}
文件 12 的 13:SafeMath.sol
pragma solidity ^0.7.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
文件 13 的 13:StargateComposer.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./interfaces/IStargateRouter.sol";
import "./interfaces/IStargateReceiver.sol";
import "./interfaces/IStargateEthVault.sol";
import "./util/BytesLib.sol";
import "./util/SafeCall.sol";
interface IStargateBridge {
function quoteLayerZeroFee(
uint16 _chainId,
uint8 _functionType,
bytes calldata _toAddress,
bytes calldata _transferAndCallPayload,
IStargateRouter.lzTxObj memory _lzTxParams
) external view returns (uint256, uint256);
}
interface IPool {
function token() external view returns (address);
function convertRate() external view returns (uint256);
}
interface IStargateFactory {
function getPool(uint256 _poolId) external view returns (address);
}
contract StargateComposer is IStargateRouter, IStargateReceiver, Ownable, ReentrancyGuard {
using BytesLib for bytes;
using SafeCall for address;
using Address for address;
using SafeERC20 for IERC20;
using SafeMath for uint256;
bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private dstGasReserve = 40000;
uint256 private transferOverhead = 20000;
uint256 private _swapStatus = _NOT_ENTERED;
IStargateBridge public immutable stargateBridge;
IStargateRouter public immutable stargateRouter;
address public immutable factory;
uint256 public wethPoolId;
struct PoolInfo {
address token;
address poolAddress;
uint256 convertRate;
}
mapping(uint16 => address) public peers;
mapping(uint256 => address) public stargateEthVaults;
mapping(uint16 => mapping(bytes => mapping(uint256 => bytes32))) public payloadHashes;
mapping(uint256 => PoolInfo) public poolIdToInfo;
modifier nonSwapReentrant() {
require(_swapStatus != _ENTERED, "Stargate: reentrant call");
_swapStatus = _ENTERED;
_;
_swapStatus = _NOT_ENTERED;
}
event CachedSwapSaved(
uint16 chainId,
bytes srcAddress,
uint256 nonce,
bytes reason
);
event ComposedTokenTransferFailed(
address token,
address intendedReceiver,
uint amountLD
);
struct SwapAmount {
uint256 amountLD;
uint256 minAmountLD;
}
constructor(address _stargateBridge, address _stargateRouter, address _stargateEthVault, uint256 _wethPoolId) {
stargateBridge = IStargateBridge(_stargateBridge);
stargateRouter = IStargateRouter(_stargateRouter);
wethPoolId = _wethPoolId;
setStargateEthVaults(_wethPoolId, _stargateEthVault);
(bool success, bytes memory data) = _stargateRouter.staticcall(abi.encodeWithSignature("factory()"));
require(success, "Stargate: invalid factory address");
factory = abi.decode(data, (address));
}
function addLiquidity(
uint256 _poolId,
uint256 _amountLD,
address _to
) external override {
PoolInfo memory poolInfo = _getPoolInfo(_poolId);
if (poolInfo.convertRate > 1) _amountLD = _amountLD.div(poolInfo.convertRate).mul(poolInfo.convertRate);
IERC20(poolInfo.token).safeTransferFrom(msg.sender, address(this), _amountLD);
stargateRouter.addLiquidity(_poolId, _amountLD, _to);
}
function redeemRemote(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
uint256 _minAmountLD,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external override payable nonReentrant {
IERC20 lpToken = IERC20(_getPoolInfo(_srcPoolId).poolAddress);
lpToken.safeTransferFrom(msg.sender, address(this), _amountLP);
stargateRouter.redeemRemote{value: msg.value}(
_dstChainId,
_srcPoolId,
_dstPoolId,
_refundAddress,
_amountLP,
_minAmountLD,
_to,
_lzTxParams
);
}
function redeemLocal(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLP,
bytes calldata _to,
lzTxObj memory _lzTxParams
) external override payable nonReentrant {
IERC20 lpToken = IERC20(_getPoolInfo(_srcPoolId).poolAddress);
lpToken.safeTransferFrom(msg.sender, address(this), _amountLP);
stargateRouter.redeemLocal{value: msg.value}(
_dstChainId,
_srcPoolId,
_dstPoolId,
_refundAddress,
_amountLP,
_to,
_lzTxParams
);
}
function instantRedeemLocal(
uint16 _srcPoolId,
uint256 _amountLP,
address _to
) external override nonReentrant returns (uint256 amountSD) {
IERC20 lpToken = IERC20(_getPoolInfo(_srcPoolId).poolAddress);
uint balanceBefore = lpToken.balanceOf(address(this));
lpToken.safeTransferFrom(msg.sender, address(this), _amountLP);
amountSD = stargateRouter.instantRedeemLocal(_srcPoolId, _amountLP, _to);
uint balanceAfter = lpToken.balanceOf(address(this));
uint diff = balanceAfter - balanceBefore;
if (diff > 0) lpToken.safeTransfer(msg.sender, diff);
}
function sendCredits(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress
) external payable override nonReentrant {
stargateRouter.sendCredits{value: msg.value}(_dstChainId, _srcPoolId, _dstPoolId, _refundAddress);
}
function quoteLayerZeroFee(
uint16 _chainId,
uint8 _functionType,
bytes calldata _toAddress,
bytes calldata _transferAndCallPayload,
IStargateRouter.lzTxObj memory _lzTxParams
) external view override returns(uint256, uint256) {
bytes memory newPayload;
bytes memory peer;
if(_transferAndCallPayload.length > 0) {
newPayload = _buildPayload(_toAddress, _transferAndCallPayload);
peer = _getPeer(_chainId);
_lzTxParams.dstGasForCall += dstGasReserve + transferOverhead;
} else {
newPayload = "";
peer = _toAddress;
}
return stargateBridge.quoteLayerZeroFee(_chainId, _functionType, peer, newPayload, _lzTxParams);
}
function swap(
uint16 _dstChainId,
uint256 _srcPoolId,
uint256 _dstPoolId,
address payable _refundAddress,
uint256 _amountLD,
uint256 _minAmountLD,
IStargateRouter.lzTxObj memory _lzTxParams,
bytes calldata _to,
bytes calldata _payload
) external override payable nonSwapReentrant {
bytes memory newPayload;
bytes memory peer;
if(_payload.length > 0) {
newPayload = _buildPayload(_to, _payload);
peer = _getPeer(_dstChainId);
_lzTxParams.dstGasForCall += dstGasReserve + transferOverhead;
} else {
newPayload = "";
peer = _to;
}
if(isEthPool(_srcPoolId)) {
require(msg.value > _amountLD, "Stargate: msg.value must be > _swapAmount.amountLD");
IStargateEthVault(stargateEthVaults[_srcPoolId]).deposit{value: _amountLD}();
IStargateEthVault(stargateEthVaults[_srcPoolId]).approve(address(stargateRouter), _amountLD);
} else {
PoolInfo memory poolInfo = _getPoolInfo(_srcPoolId);
if (poolInfo.convertRate > 1) _amountLD = _amountLD.div(poolInfo.convertRate).mul(poolInfo.convertRate);
IERC20(poolInfo.token).safeTransferFrom(msg.sender, address(this), _amountLD);
}
stargateRouter.swap{value: isEthPool(_srcPoolId) ? msg.value - _amountLD : msg.value}(
_dstChainId,
_srcPoolId,
_dstPoolId,
_refundAddress,
_amountLD,
_minAmountLD,
_lzTxParams,
peer,
newPayload
);
}
function swapETHAndCall(
uint16 _dstChainId,
address payable _refundAddress,
bytes calldata _to,
SwapAmount memory _swapAmount,
IStargateRouter.lzTxObj memory _lzTxParams,
bytes calldata _payload
) external payable nonSwapReentrant {
bytes memory newPayload;
bytes memory peer;
if(_payload.length > 0) {
newPayload = _buildPayload(_to, _payload);
peer = _getPeer(_dstChainId);
_lzTxParams.dstGasForCall += dstGasReserve + transferOverhead;
} else {
newPayload = "";
peer = _to;
}
{
require(msg.value > _swapAmount.amountLD, "Stargate: msg.value must be > _swapAmount.amountLD");
require(stargateEthVaults[wethPoolId] != address(0), "Stargate: Pool does not exist");
IStargateEthVault(stargateEthVaults[wethPoolId]).deposit{value: _swapAmount.amountLD}();
IStargateEthVault(stargateEthVaults[wethPoolId]).approve(address(stargateRouter), _swapAmount.amountLD);
}
stargateRouter.swap{value: (msg.value - _swapAmount.amountLD)}(
_dstChainId,
wethPoolId,
wethPoolId,
_refundAddress,
_swapAmount.amountLD,
_swapAmount.minAmountLD,
_lzTxParams,
peer,
newPayload
);
}
function _buildPayload(
bytes calldata _to,
bytes calldata _payload
) internal view returns (bytes memory) {
require(_to.length == 20, "Stargate: invalid to address");
return abi.encodePacked(_to, msg.sender, _payload);
}
function _getPeer(uint16 _dstChainId) internal view returns(bytes memory) {
address peerAddr = peers[_dstChainId];
require(peerAddr != address(0), "Stargate: peer not found");
return abi.encodePacked(peerAddr);
}
function addLiquidityETH() external payable {
require(msg.value > 0, "Stargate: msg.value is 0");
uint256 amountLD = msg.value;
require(stargateEthVaults[wethPoolId] != address(0), "Stargate: Pool does not exist");
IStargateEthVault(stargateEthVaults[wethPoolId]).deposit{value: amountLD}();
IStargateEthVault(stargateEthVaults[wethPoolId]).approve(address(stargateRouter), amountLD);
stargateRouter.addLiquidity(wethPoolId, amountLD, msg.sender);
}
function sgReceive(
uint16 _srcChainId,
bytes memory _srcAddress,
uint256 _nonce,
address _token,
uint256 _amountLD,
bytes memory _payload
) external override {
require(msg.sender == address(stargateRouter), "Stargate: only router");
if (_payload.length <= 40) return;
address intendedReceiver = _payload.toAddress(0);
(bool success, bytes memory data) = _token.call(abi.encodeWithSelector(SELECTOR, intendedReceiver, _amountLD));
if (success && (data.length == 0 || abi.decode(data, (bool)))) {
if (!intendedReceiver.isContract()) return;
bytes memory callData = abi.encodeWithSelector(
IStargateReceiver.sgReceive.selector,
_srcChainId,
abi.encodePacked(_payload.toAddress(20)),
_nonce,
_token,
_amountLD,
_payload.slice(40, _payload.length - 40)
);
uint256 externalGas = gasleft() - dstGasReserve;
(bool safeCallSuccess, bytes memory reason) = intendedReceiver.safeCall(externalGas, 0, 150, callData);
if (!safeCallSuccess) {
payloadHashes[_srcChainId][_srcAddress][_nonce] = keccak256(abi.encodePacked(intendedReceiver, callData));
emit CachedSwapSaved(_srcChainId, _srcAddress, _nonce, reason);
}
} else {
emit ComposedTokenTransferFailed(_token, intendedReceiver, _amountLD);
}
}
function clearCachedSwap(
uint16 _srcChainId,
bytes calldata _srcAddress,
uint64 _nonce,
address _receiver,
bytes calldata _sgReceiveCallData
) external nonReentrant {
bytes32 hash = keccak256(abi.encodePacked(_receiver, _sgReceiveCallData));
require(payloadHashes[_srcChainId][_srcAddress][_nonce] == hash, "Stargate: invalid hash");
delete payloadHashes[_srcChainId][_srcAddress][_nonce];
(bool success, bytes memory reason) = _receiver.safeCall(gasleft(), 0, 150, _sgReceiveCallData);
if (!success) {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
function setDstGasReserve(uint256 _dstGasReserve) onlyOwner external {
dstGasReserve = _dstGasReserve;
}
function setTransferOverhead(uint256 _transferOverhead) onlyOwner external {
transferOverhead = _transferOverhead;
}
function setStargateEthVaults(uint256 _poolId, address _stargateEthVault) onlyOwner public {
stargateEthVaults[_poolId] = _stargateEthVault;
}
function setWethPoolId(uint256 _wethPoolId) onlyOwner external {
wethPoolId = _wethPoolId;
}
function setPeer(uint16 _chainId, address _peer) onlyOwner external {
require(peers[_chainId] == address(0), "Stargate: peer already set");
peers[_chainId] = _peer;
}
function recoverToken(address _token, address _to, uint256 _amount) external onlyOwner {
IERC20(_token).safeTransfer(_to, _amount);
}
function isSending() external view returns (bool) {
return _swapStatus == _ENTERED;
}
function isEthPool(uint256 _srcPoolId) internal view returns (bool) {
return stargateEthVaults[_srcPoolId] != address(0);
}
function getPoolInfo(uint256 _poolId) external returns (PoolInfo memory poolInfo) {
return _getPoolInfo(_poolId);
}
function _getPoolInfo(uint256 _poolId) internal returns (PoolInfo memory poolInfo) {
if (poolIdToInfo[_poolId].poolAddress != address(0)) {
return poolIdToInfo[_poolId];
}
address pool = IStargateFactory(factory).getPool(_poolId);
require(address(pool) != address(0), "Stargate: pool does not exist");
IERC20(pool).safeApprove(address(stargateRouter), type(uint256).max);
address token = IPool(pool).token();
require(address(token) != address(0), "Stargate: token does not exist");
IERC20(token).safeApprove(address(stargateRouter), type(uint256).max);
uint256 convertRate = IPool(pool).convertRate();
poolInfo = PoolInfo({token: token, poolAddress: pool, convertRate: convertRate});
poolIdToInfo[_poolId] = poolInfo;
}
}
{
"compilationTarget": {
"contracts/StargateComposer.sol": "StargateComposer"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_stargateBridge","type":"address"},{"internalType":"address","name":"_stargateRouter","type":"address"},{"internalType":"address","name":"_stargateEthVault","type":"address"},{"internalType":"uint256","name":"_wethPoolId","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"chainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"srcAddress","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"CachedSwapSaved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"intendedReceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountLD","type":"uint256"}],"name":"ComposedTokenTransferFailed","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"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256","name":"_amountLD","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"addLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"addLiquidityETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"_nonce","type":"uint64"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"bytes","name":"_sgReceiveCallData","type":"bytes"}],"name":"clearCachedSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"getPoolInfo","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"convertRate","type":"uint256"}],"internalType":"struct StargateComposer.PoolInfo","name":"poolInfo","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcPoolId","type":"uint16"},{"internalType":"uint256","name":"_amountLP","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"instantRedeemLocal","outputs":[{"internalType":"uint256","name":"amountSD","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isSending","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"payloadHashes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"peers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolIdToInfo","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint256","name":"convertRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"uint8","name":"_functionType","type":"uint8"},{"internalType":"bytes","name":"_toAddress","type":"bytes"},{"internalType":"bytes","name":"_transferAndCallPayload","type":"bytes"},{"components":[{"internalType":"uint256","name":"dstGasForCall","type":"uint256"},{"internalType":"uint256","name":"dstNativeAmount","type":"uint256"},{"internalType":"bytes","name":"dstNativeAddr","type":"bytes"}],"internalType":"struct IStargateRouter.lzTxObj","name":"_lzTxParams","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"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"address payable","name":"_refundAddress","type":"address"},{"internalType":"uint256","name":"_amountLP","type":"uint256"},{"internalType":"bytes","name":"_to","type":"bytes"},{"components":[{"internalType":"uint256","name":"dstGasForCall","type":"uint256"},{"internalType":"uint256","name":"dstNativeAmount","type":"uint256"},{"internalType":"bytes","name":"dstNativeAddr","type":"bytes"}],"internalType":"struct IStargateRouter.lzTxObj","name":"_lzTxParams","type":"tuple"}],"name":"redeemLocal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"address payable","name":"_refundAddress","type":"address"},{"internalType":"uint256","name":"_amountLP","type":"uint256"},{"internalType":"uint256","name":"_minAmountLD","type":"uint256"},{"internalType":"bytes","name":"_to","type":"bytes"},{"components":[{"internalType":"uint256","name":"dstGasForCall","type":"uint256"},{"internalType":"uint256","name":"dstNativeAmount","type":"uint256"},{"internalType":"bytes","name":"dstNativeAddr","type":"bytes"}],"internalType":"struct IStargateRouter.lzTxObj","name":"_lzTxParams","type":"tuple"}],"name":"redeemRemote","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"address payable","name":"_refundAddress","type":"address"}],"name":"sendCredits","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_dstGasReserve","type":"uint256"}],"name":"setDstGasReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"address","name":"_peer","type":"address"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_stargateEthVault","type":"address"}],"name":"setStargateEthVaults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_transferOverhead","type":"uint256"}],"name":"setTransferOverhead","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_wethPoolId","type":"uint256"}],"name":"setWethPoolId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amountLD","type":"uint256"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"sgReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stargateBridge","outputs":[{"internalType":"contract IStargateBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stargateEthVaults","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stargateRouter","outputs":[{"internalType":"contract IStargateRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"address payable","name":"_refundAddress","type":"address"},{"internalType":"uint256","name":"_amountLD","type":"uint256"},{"internalType":"uint256","name":"_minAmountLD","type":"uint256"},{"components":[{"internalType":"uint256","name":"dstGasForCall","type":"uint256"},{"internalType":"uint256","name":"dstNativeAmount","type":"uint256"},{"internalType":"bytes","name":"dstNativeAddr","type":"bytes"}],"internalType":"struct IStargateRouter.lzTxObj","name":"_lzTxParams","type":"tuple"},{"internalType":"bytes","name":"_to","type":"bytes"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"swap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"address payable","name":"_refundAddress","type":"address"},{"internalType":"bytes","name":"_to","type":"bytes"},{"components":[{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"}],"internalType":"struct StargateComposer.SwapAmount","name":"_swapAmount","type":"tuple"},{"components":[{"internalType":"uint256","name":"dstGasForCall","type":"uint256"},{"internalType":"uint256","name":"dstNativeAmount","type":"uint256"},{"internalType":"bytes","name":"dstNativeAddr","type":"bytes"}],"internalType":"struct IStargateRouter.lzTxObj","name":"_lzTxParams","type":"tuple"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"swapETHAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wethPoolId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]