文件 1 的 16:AggregatorV3Interface.sol
pragma solidity ^0.7.6;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
文件 2 的 16: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;
}
}
文件 3 的 16:Factory.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./Pool.sol";
contract Factory is Ownable {
using SafeMath for uint256;
mapping(uint256 => Pool) public getPool;
address[] public allPools;
address public immutable router;
address public defaultFeeLibrary;
modifier onlyRouter() {
require(msg.sender == router, "Stargate: caller must be Router.");
_;
}
constructor(address _router) {
require(_router != address(0x0), "Stargate: _router cant be 0x0");
router = _router;
}
function setDefaultFeeLibrary(address _defaultFeeLibrary) external onlyOwner {
require(_defaultFeeLibrary != address(0x0), "Stargate: fee library cant be 0x0");
defaultFeeLibrary = _defaultFeeLibrary;
}
function allPoolsLength() external view returns (uint256) {
return allPools.length;
}
function createPool(
uint256 _poolId,
address _token,
uint8 _sharedDecimals,
uint8 _localDecimals,
string memory _name,
string memory _symbol
) public onlyRouter returns (address poolAddress) {
require(address(getPool[_poolId]) == address(0x0), "Stargate: Pool already created");
Pool pool = new Pool(_poolId, router, _token, _sharedDecimals, _localDecimals, defaultFeeLibrary, _name, _symbol);
getPool[_poolId] = pool;
poolAddress = address(pool);
allPools.push(poolAddress);
}
function renounceOwnership() public override onlyOwner {}
}
文件 4 的 16: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 的 16:ILayerZeroEndpoint.sol
pragma solidity >=0.5.0;
import "./ILayerZeroUserApplicationConfig.sol";
interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;
function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;
function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);
function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);
function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);
function getChainId() external view returns (uint16);
function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;
function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);
function getSendLibraryAddress(address _userApplication) external view returns (address);
function getReceiveLibraryAddress(address _userApplication) external view returns (address);
function isSendingPayload() external view returns (bool);
function isReceivingPayload() external view returns (bool);
function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);
function getSendVersion(address _userApplication) external view returns (uint16);
function getReceiveVersion(address _userApplication) external view returns (uint16);
}
文件 6 的 16:ILayerZeroReceiver.sol
pragma solidity >=0.5.0;
interface ILayerZeroReceiver {
function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;
}
文件 7 的 16:ILayerZeroUserApplicationConfig.sol
pragma solidity >=0.5.0;
interface ILayerZeroUserApplicationConfig {
function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;
function setSendVersion(uint16 _version) external;
function setReceiveVersion(uint16 _version) external;
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}
文件 8 的 16:IStargateFeeLibrary.sol
pragma solidity ^0.7.6;
pragma abicoder v2;
import "../Pool.sol";
interface IStargateFeeLibrary {
function getFees(
uint256 _srcPoolId,
uint256 _dstPoolId,
uint16 _dstChainId,
address _from,
uint256 _amountSD
) external returns (Pool.SwapObj memory s);
function getVersion() external view returns (string memory);
}
文件 9 的 16:IStargateLPStaking.sol
pragma solidity ^0.7.6;
pragma abicoder v2;
interface IStargateLPStaking {
function poolInfo(uint256 _poolIndex)
external
view
returns (
address,
uint256,
uint256,
uint256
);
}
文件 10 的 16:LPTokenERC20.sol
pragma solidity 0.7.6;
import "@openzeppelin/contracts/math/SafeMath.sol";
contract LPTokenERC20 {
using SafeMath for uint256;
string public name;
string public symbol;
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
bytes32 public DOMAIN_SEPARATOR;
uint256 public decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
mapping(address => uint256) public nonces;
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
constructor(string memory _name, string memory _symbol) {
name = _name;
symbol = _symbol;
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes("1")),
chainId,
address(this)
)
);
}
function _mint(address to, uint256 value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint256 value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(
address owner,
address spender,
uint256 value
) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(
address from,
address to,
uint256 value
) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint256 value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint256 value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool) {
if (allowance[from][msg.sender] != uint256(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(deadline >= block.timestamp, "Bridge: EXPIRED");
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, "Bridge: INVALID_SIGNATURE");
_approve(owner, spender, value);
}
}
文件 11 的 16:LzApp.sol
pragma solidity 0.7.6;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@layerzerolabs/layerzero-core/contracts/interfaces/ILayerZeroReceiver.sol";
import "@layerzerolabs/layerzero-core/contracts/interfaces/ILayerZeroEndpoint.sol";
import "@layerzerolabs/layerzero-core/contracts/interfaces/ILayerZeroUserApplicationConfig.sol";
abstract contract LzApp is Ownable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {
ILayerZeroEndpoint public immutable lzEndpoint;
mapping(uint16 => bytes) public trustedRemoteLookup;
mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup;
address public precrime;
event SetPrecrime(address precrime);
event SetTrustedRemote(uint16 _remoteChainId, bytes _path);
event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);
event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);
constructor(address _endpoint) {
lzEndpoint = ILayerZeroEndpoint(_endpoint);
}
function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) public virtual override {
require(_msgSender() == address(lzEndpoint), "LzApp: invalid endpoint caller");
bytes memory trustedRemote = trustedRemoteLookup[_srcChainId];
require(_srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote), "LzApp: invalid source sending contract");
_blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);
}
function _blockingLzReceive(uint16 _srcChainId, bytes memory _srcAddress, uint64 _nonce, bytes memory _payload) internal virtual;
function _lzSend(uint16 _dstChainId, bytes memory _payload, address payable _refundAddress, address _zroPaymentAddress, bytes memory _adapterParams, uint _nativeFee) internal virtual {
bytes memory trustedRemote = trustedRemoteLookup[_dstChainId];
require(trustedRemote.length != 0, "LzApp: destination chain is not a trusted source");
lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);
}
function _checkGasLimit(uint16 _dstChainId, uint16 _type, bytes memory _adapterParams, uint _extraGas) internal view virtual {
uint providedGasLimit = _getGasLimit(_adapterParams);
uint minGasLimit = minDstGasLookup[_dstChainId][_type] + _extraGas;
require(minGasLimit > 0, "LzApp: minGasLimit not set");
require(providedGasLimit >= minGasLimit, "LzApp: gas limit is too low");
}
function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint gasLimit) {
require(_adapterParams.length >= 34, "LzApp: invalid adapterParams");
assembly {
gasLimit := mload(add(_adapterParams, 34))
}
}
function getConfig(uint16 _version, uint16 _chainId, address, uint _configType) external view returns (bytes memory) {
return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);
}
function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external override onlyOwner {
lzEndpoint.setConfig(_version, _chainId, _configType, _config);
}
function setSendVersion(uint16 _version) external override onlyOwner {
lzEndpoint.setSendVersion(_version);
}
function setReceiveVersion(uint16 _version) external override onlyOwner {
lzEndpoint.setReceiveVersion(_version);
}
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {
lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
}
function setTrustedRemote(uint16 _srcChainId, bytes calldata _path) external onlyOwner {
trustedRemoteLookup[_srcChainId] = _path;
emit SetTrustedRemote(_srcChainId, _path);
}
function setPrecrime(address _precrime) external onlyOwner {
precrime = _precrime;
emit SetPrecrime(_precrime);
}
function setMinDstGas(uint16 _dstChainId, uint16 _packetType, uint _minGas) external onlyOwner {
require(_minGas > 0, "LzApp: invalid minGas");
minDstGasLookup[_dstChainId][_packetType] = _minGas;
emit SetMinDstGas(_dstChainId, _packetType, _minGas);
}
function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) {
bytes memory trustedSource = trustedRemoteLookup[_srcChainId];
return keccak256(trustedSource) == keccak256(_srcAddress);
}
}
文件 12 的 16: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;
}
}
文件 13 的 16:Pool.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./LPTokenERC20.sol";
import "./interfaces/IStargateFeeLibrary.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
contract Pool is LPTokenERC20, ReentrancyGuard {
using SafeMath for uint256;
bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));
uint256 public constant BP_DENOMINATOR = 10000;
struct ChainPath {
bool ready;
uint16 dstChainId;
uint256 dstPoolId;
uint256 weight;
uint256 balance;
uint256 lkb;
uint256 credits;
uint256 idealBalance;
}
struct SwapObj {
uint256 amount;
uint256 eqFee;
uint256 eqReward;
uint256 lpFee;
uint256 protocolFee;
uint256 lkbRemove;
}
struct CreditObj {
uint256 credits;
uint256 idealBalance;
}
ChainPath[] public chainPaths;
mapping(uint16 => mapping(uint256 => uint256)) public chainPathIndexLookup;
uint256 public immutable poolId;
uint256 public sharedDecimals;
uint256 public localDecimals;
uint256 public immutable convertRate;
address public immutable token;
address public immutable router;
bool public stopSwap;
uint256 public totalLiquidity;
uint256 public totalWeight;
uint256 public mintFeeBP;
uint256 public protocolFeeBalance;
uint256 public mintFeeBalance;
uint256 public eqFeePool;
address public feeLibrary;
uint256 public deltaCredit;
bool public batched;
bool public defaultSwapMode;
bool public defaultLPMode;
uint256 public swapDeltaBP;
uint256 public lpDeltaBP;
event Mint(address to, uint256 amountLP, uint256 amountSD, uint256 mintFeeAmountSD);
event Burn(address from, uint256 amountLP, uint256 amountSD);
event RedeemLocalCallback(address _to, uint256 _amountSD, uint256 _amountToMintSD);
event Swap(
uint16 chainId,
uint256 dstPoolId,
address from,
uint256 amountSD,
uint256 eqReward,
uint256 eqFee,
uint256 protocolFee,
uint256 lpFee
);
event SendCredits(uint16 dstChainId, uint256 dstPoolId, uint256 credits, uint256 idealBalance);
event RedeemRemote(uint16 chainId, uint256 dstPoolId, address from, uint256 amountLP, uint256 amountSD);
event RedeemLocal(address from, uint256 amountLP, uint256 amountSD, uint16 chainId, uint256 dstPoolId, bytes to);
event InstantRedeemLocal(address from, uint256 amountLP, uint256 amountSD, address to);
event CreditChainPath(uint16 chainId, uint256 srcPoolId, uint256 amountSD, uint256 idealBalance);
event SwapRemote(address to, uint256 amountSD, uint256 protocolFee, uint256 dstFee);
event WithdrawRemote(uint16 srcChainId, uint256 srcPoolId, uint256 swapAmount, uint256 mintAmount);
event ChainPathUpdate(uint16 dstChainId, uint256 dstPoolId, uint256 weight);
event FeesUpdated(uint256 mintFeeBP);
event FeeLibraryUpdated(address feeLibraryAddr);
event StopSwapUpdated(bool swapStop);
event WithdrawProtocolFeeBalance(address to, uint256 amountSD);
event WithdrawMintFeeBalance(address to, uint256 amountSD);
event DeltaParamUpdated(bool batched, uint256 swapDeltaBP, uint256 lpDeltaBP, bool defaultSwapMode, bool defaultLPMode);
modifier onlyRouter() {
require(msg.sender == router, "Stargate: only the router can call this method");
_;
}
constructor(
uint256 _poolId,
address _router,
address _token,
uint256 _sharedDecimals,
uint256 _localDecimals,
address _feeLibrary,
string memory _name,
string memory _symbol
) LPTokenERC20(_name, _symbol) {
require(_token != address(0x0), "Stargate: _token cannot be 0x0");
require(_router != address(0x0), "Stargate: _router cannot be 0x0");
poolId = _poolId;
router = _router;
token = _token;
sharedDecimals = _sharedDecimals;
decimals = uint8(_sharedDecimals);
localDecimals = _localDecimals;
convertRate = 10**(uint256(localDecimals).sub(sharedDecimals));
totalWeight = 0;
feeLibrary = _feeLibrary;
batched = false;
defaultSwapMode = true;
defaultLPMode = true;
}
function getChainPathsLength() public view returns (uint256) {
return chainPaths.length;
}
function mint(address _to, uint256 _amountLD) external nonReentrant onlyRouter returns (uint256) {
return _mintLocal(_to, _amountLD, true, true);
}
function swap(
uint16 _dstChainId,
uint256 _dstPoolId,
address _from,
uint256 _amountLD,
uint256 _minAmountLD,
bool newLiquidity
) external nonReentrant onlyRouter returns (SwapObj memory) {
require(!stopSwap, "Stargate: swap func stopped");
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
require(cp.ready == true, "Stargate: counter chainPath is not ready");
uint256 amountSD = amountLDtoSD(_amountLD);
uint256 minAmountSD = amountLDtoSD(_minAmountLD);
SwapObj memory s = IStargateFeeLibrary(feeLibrary).getFees(poolId, _dstPoolId, _dstChainId, _from, amountSD);
eqFeePool = eqFeePool.sub(s.eqReward);
s.amount = amountSD.sub(s.eqFee).sub(s.protocolFee).sub(s.lpFee);
require(s.amount.add(s.eqReward) >= minAmountSD, "Stargate: slippage too high");
s.lkbRemove = amountSD.sub(s.lpFee).add(s.eqReward);
require(cp.balance >= s.lkbRemove, "Stargate: dst balance too low");
cp.balance = cp.balance.sub(s.lkbRemove);
if (newLiquidity) {
deltaCredit = deltaCredit.add(amountSD).add(s.eqReward);
} else if (s.eqReward > 0) {
deltaCredit = deltaCredit.add(s.eqReward);
}
if (!batched || deltaCredit >= totalLiquidity.mul(swapDeltaBP).div(BP_DENOMINATOR)) {
_delta(defaultSwapMode);
}
emit Swap(_dstChainId, _dstPoolId, _from, s.amount, s.eqReward, s.eqFee, s.protocolFee, s.lpFee);
return s;
}
function sendCredits(uint16 _dstChainId, uint256 _dstPoolId) external nonReentrant onlyRouter returns (CreditObj memory c) {
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
require(cp.ready == true, "Stargate: counter chainPath is not ready");
cp.lkb = cp.lkb.add(cp.credits);
c.idealBalance = totalLiquidity.mul(cp.weight).div(totalWeight);
c.credits = cp.credits;
cp.credits = 0;
emit SendCredits(_dstChainId, _dstPoolId, c.credits, c.idealBalance);
}
function redeemRemote(
uint16 _dstChainId,
uint256 _dstPoolId,
address _from,
uint256 _amountLP
) external nonReentrant onlyRouter {
require(_from != address(0x0), "Stargate: _from cannot be 0x0");
uint256 amountSD = _burnLocal(_from, _amountLP);
if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
_delta(defaultLPMode);
}
uint256 amountLD = amountSDtoLD(amountSD);
emit RedeemRemote(_dstChainId, _dstPoolId, _from, _amountLP, amountLD);
}
function instantRedeemLocal(
address _from,
uint256 _amountLP,
address _to
) external nonReentrant onlyRouter returns (uint256 amountSD) {
require(_from != address(0x0), "Stargate: _from cannot be 0x0");
uint256 _deltaCredit = deltaCredit;
uint256 _capAmountLP = _amountSDtoLP(_deltaCredit);
if (_amountLP > _capAmountLP) _amountLP = _capAmountLP;
amountSD = _burnLocal(_from, _amountLP);
deltaCredit = _deltaCredit.sub(amountSD);
uint256 amountLD = amountSDtoLD(amountSD);
_safeTransfer(token, _to, amountLD);
emit InstantRedeemLocal(_from, _amountLP, amountSD, _to);
}
function redeemLocal(
address _from,
uint256 _amountLP,
uint16 _dstChainId,
uint256 _dstPoolId,
bytes calldata _to
) external nonReentrant onlyRouter returns (uint256 amountSD) {
require(_from != address(0x0), "Stargate: _from cannot be 0x0");
require(chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]].ready == true, "Stargate: counter chainPath is not ready");
amountSD = _burnLocal(_from, _amountLP);
if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
_delta(false);
}
emit RedeemLocal(_from, _amountLP, amountSD, _dstChainId, _dstPoolId, _to);
}
function creditChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
CreditObj memory _c
) external nonReentrant onlyRouter {
ChainPath storage cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
cp.balance = cp.balance.add(_c.credits);
if (cp.idealBalance != _c.idealBalance) {
cp.idealBalance = _c.idealBalance;
}
emit CreditChainPath(_dstChainId, _dstPoolId, _c.credits, _c.idealBalance);
}
function swapRemote(
uint16 _srcChainId,
uint256 _srcPoolId,
address _to,
SwapObj memory _s
) external nonReentrant onlyRouter returns (uint256 amountLD) {
totalLiquidity = totalLiquidity.add(_s.lpFee);
eqFeePool = eqFeePool.add(_s.eqFee);
protocolFeeBalance = protocolFeeBalance.add(_s.protocolFee);
uint256 chainPathIndex = chainPathIndexLookup[_srcChainId][_srcPoolId];
chainPaths[chainPathIndex].lkb = chainPaths[chainPathIndex].lkb.sub(_s.lkbRemove);
amountLD = amountSDtoLD(_s.amount.add(_s.eqReward));
_safeTransfer(token, _to, amountLD);
emit SwapRemote(_to, _s.amount.add(_s.eqReward), _s.protocolFee, _s.eqFee);
}
function redeemLocalCallback(
uint16 _srcChainId,
uint256 _srcPoolId,
address _to,
uint256 _amountSD,
uint256 _amountToMintSD
) external nonReentrant onlyRouter {
if (_amountToMintSD > 0) {
_mintLocal(_to, amountSDtoLD(_amountToMintSD), false, false);
}
ChainPath storage cp = getAndCheckCP(_srcChainId, _srcPoolId);
cp.lkb = cp.lkb.sub(_amountSD);
uint256 amountLD = amountSDtoLD(_amountSD);
_safeTransfer(token, _to, amountLD);
emit RedeemLocalCallback(_to, _amountSD, _amountToMintSD);
}
function redeemLocalCheckOnRemote(
uint16 _srcChainId,
uint256 _srcPoolId,
uint256 _amountSD
) external nonReentrant onlyRouter returns (uint256 swapAmount, uint256 mintAmount) {
ChainPath storage cp = getAndCheckCP(_srcChainId, _srcPoolId);
if (_amountSD > cp.balance) {
mintAmount = _amountSD - cp.balance;
swapAmount = cp.balance;
cp.balance = 0;
} else {
cp.balance = cp.balance.sub(_amountSD);
swapAmount = _amountSD;
mintAmount = 0;
}
emit WithdrawRemote(_srcChainId, _srcPoolId, swapAmount, mintAmount);
}
function createChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
uint256 _weight
) external onlyRouter {
for (uint256 i = 0; i < chainPaths.length; ++i) {
ChainPath memory cp = chainPaths[i];
bool exists = cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId;
require(!exists, "Stargate: cant createChainPath of existing dstChainId and _dstPoolId");
}
totalWeight = totalWeight.add(_weight);
chainPathIndexLookup[_dstChainId][_dstPoolId] = chainPaths.length;
chainPaths.push(ChainPath(false, _dstChainId, _dstPoolId, _weight, 0, 0, 0, 0));
emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
}
function setWeightForChainPath(
uint16 _dstChainId,
uint256 _dstPoolId,
uint16 _weight
) external onlyRouter {
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
totalWeight = totalWeight.sub(cp.weight).add(_weight);
cp.weight = _weight;
emit ChainPathUpdate(_dstChainId, _dstPoolId, _weight);
}
function setFee(uint256 _mintFeeBP) external onlyRouter {
require(_mintFeeBP <= BP_DENOMINATOR, "Bridge: cum fees > 100%");
mintFeeBP = _mintFeeBP;
emit FeesUpdated(mintFeeBP);
}
function setFeeLibrary(address _feeLibraryAddr) external onlyRouter {
require(_feeLibraryAddr != address(0x0), "Stargate: fee library cant be 0x0");
feeLibrary = _feeLibraryAddr;
emit FeeLibraryUpdated(_feeLibraryAddr);
}
function setSwapStop(bool _swapStop) external onlyRouter {
stopSwap = _swapStop;
emit StopSwapUpdated(_swapStop);
}
function setDeltaParam(
bool _batched,
uint256 _swapDeltaBP,
uint256 _lpDeltaBP,
bool _defaultSwapMode,
bool _defaultLPMode
) external onlyRouter {
require(_swapDeltaBP <= BP_DENOMINATOR && _lpDeltaBP <= BP_DENOMINATOR, "Stargate: wrong Delta param");
batched = _batched;
swapDeltaBP = _swapDeltaBP;
lpDeltaBP = _lpDeltaBP;
defaultSwapMode = _defaultSwapMode;
defaultLPMode = _defaultLPMode;
emit DeltaParamUpdated(_batched, _swapDeltaBP, _lpDeltaBP, _defaultSwapMode, _defaultLPMode);
}
function callDelta(bool _fullMode) external onlyRouter {
_delta(_fullMode);
}
function activateChainPath(uint16 _dstChainId, uint256 _dstPoolId) external onlyRouter {
ChainPath storage cp = getAndCheckCP(_dstChainId, _dstPoolId);
require(cp.ready == false, "Stargate: chainPath is already active");
cp.ready = true;
}
function withdrawProtocolFeeBalance(address _to) external onlyRouter {
if (protocolFeeBalance > 0) {
uint256 amountOfLD = amountSDtoLD(protocolFeeBalance);
protocolFeeBalance = 0;
_safeTransfer(token, _to, amountOfLD);
emit WithdrawProtocolFeeBalance(_to, amountOfLD);
}
}
function withdrawMintFeeBalance(address _to) external onlyRouter {
if (mintFeeBalance > 0) {
uint256 amountOfLD = amountSDtoLD(mintFeeBalance);
mintFeeBalance = 0;
_safeTransfer(token, _to, amountOfLD);
emit WithdrawMintFeeBalance(_to, amountOfLD);
}
}
function amountLPtoLD(uint256 _amountLP) external view returns (uint256) {
return amountSDtoLD(_amountLPtoSD(_amountLP));
}
function _amountLPtoSD(uint256 _amountLP) internal view returns (uint256) {
require(totalSupply > 0, "Stargate: cant convert LPtoSD when totalSupply == 0");
return _amountLP.mul(totalLiquidity).div(totalSupply);
}
function _amountSDtoLP(uint256 _amountSD) internal view returns (uint256) {
require(totalLiquidity > 0, "Stargate: cant convert SDtoLP when totalLiq == 0");
return _amountSD.mul(totalSupply).div(totalLiquidity);
}
function amountSDtoLD(uint256 _amount) internal view returns (uint256) {
return _amount.mul(convertRate);
}
function amountLDtoSD(uint256 _amount) internal view returns (uint256) {
return _amount.div(convertRate);
}
function getAndCheckCP(uint16 _dstChainId, uint256 _dstPoolId) internal view returns (ChainPath storage) {
require(chainPaths.length > 0, "Stargate: no chainpaths exist");
ChainPath storage cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
require(cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId, "Stargate: local chainPath does not exist");
return cp;
}
function getChainPath(uint16 _dstChainId, uint256 _dstPoolId) external view returns (ChainPath memory) {
ChainPath memory cp = chainPaths[chainPathIndexLookup[_dstChainId][_dstPoolId]];
require(cp.dstChainId == _dstChainId && cp.dstPoolId == _dstPoolId, "Stargate: local chainPath does not exist");
return cp;
}
function _burnLocal(address _from, uint256 _amountLP) internal returns (uint256) {
require(totalSupply > 0, "Stargate: cant burn when totalSupply == 0");
uint256 amountOfLPTokens = balanceOf[_from];
require(amountOfLPTokens >= _amountLP, "Stargate: not enough LP tokens to burn");
uint256 amountSD = _amountLP.mul(totalLiquidity).div(totalSupply);
totalLiquidity = totalLiquidity.sub(amountSD);
_burn(_from, _amountLP);
emit Burn(_from, _amountLP, amountSD);
return amountSD;
}
function _delta(bool fullMode) internal {
if (deltaCredit > 0 && totalWeight > 0) {
uint256 cpLength = chainPaths.length;
uint256[] memory deficit = new uint256[](cpLength);
uint256 totalDeficit = 0;
for (uint256 i = 0; i < cpLength; ++i) {
ChainPath storage cp = chainPaths[i];
uint256 balLiq = totalLiquidity.mul(cp.weight).div(totalWeight);
uint256 currLiq = cp.lkb.add(cp.credits);
if (balLiq > currLiq) {
deficit[i] = balLiq - currLiq;
totalDeficit = totalDeficit.add(deficit[i]);
}
}
uint256 spent;
if (totalDeficit == 0) {
if (fullMode && deltaCredit > 0) {
for (uint256 i = 0; i < cpLength; ++i) {
ChainPath storage cp = chainPaths[i];
uint256 amtToCredit = deltaCredit.mul(cp.weight).div(totalWeight);
spent = spent.add(amtToCredit);
cp.credits = cp.credits.add(amtToCredit);
}
}
} else if (totalDeficit <= deltaCredit) {
if (fullMode) {
uint256 excessCredit = deltaCredit - totalDeficit;
for (uint256 i = 0; i < cpLength; ++i) {
if (deficit[i] > 0) {
ChainPath storage cp = chainPaths[i];
uint256 amtToCredit = deficit[i].add(excessCredit.mul(cp.weight).div(totalWeight));
spent = spent.add(amtToCredit);
cp.credits = cp.credits.add(amtToCredit);
}
}
} else {
for (uint256 i = 0; i < cpLength; ++i) {
if (deficit[i] > 0) {
ChainPath storage cp = chainPaths[i];
uint256 amtToCredit = deficit[i];
spent = spent.add(amtToCredit);
cp.credits = cp.credits.add(amtToCredit);
}
}
}
} else {
for (uint256 i = 0; i < cpLength; ++i) {
if (deficit[i] > 0) {
ChainPath storage cp = chainPaths[i];
uint256 proportionalDeficit = deficit[i].mul(deltaCredit).div(totalDeficit);
spent = spent.add(proportionalDeficit);
cp.credits = cp.credits.add(proportionalDeficit);
}
}
}
deltaCredit = deltaCredit.sub(spent);
}
}
function _mintLocal(
address _to,
uint256 _amountLD,
bool _feesEnabled,
bool _creditDelta
) internal returns (uint256 amountSD) {
require(totalWeight > 0, "Stargate: No ChainPaths exist");
amountSD = amountLDtoSD(_amountLD);
uint256 mintFeeSD = 0;
if (_feesEnabled) {
mintFeeSD = amountSD.mul(mintFeeBP).div(BP_DENOMINATOR);
amountSD = amountSD.sub(mintFeeSD);
mintFeeBalance = mintFeeBalance.add(mintFeeSD);
}
if (_creditDelta) {
deltaCredit = deltaCredit.add(amountSD);
}
uint256 amountLPTokens = amountSD;
if (totalSupply != 0) {
amountLPTokens = amountSD.mul(totalSupply).div(totalLiquidity);
}
totalLiquidity = totalLiquidity.add(amountSD);
_mint(_to, amountLPTokens);
emit Mint(_to, amountLPTokens, amountSD, mintFeeSD);
if (!batched || deltaCredit > totalLiquidity.mul(lpDeltaBP).div(BP_DENOMINATOR)) {
_delta(defaultLPMode);
}
}
function _safeTransfer(
address _token,
address _to,
uint256 _value
) private {
(bool success, bytes memory data) = _token.call(abi.encodeWithSelector(SELECTOR, _to, _value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "Stargate: TRANSFER_FAILED");
}
}
文件 14 的 16: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;
}
}
文件 15 的 16: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;
}
}
文件 16 的 16:StargateFeeLibraryV07.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import "../interfaces/IStargateFeeLibrary.sol";
import "../Pool.sol";
import "../Factory.sol";
import "../interfaces/IStargateLPStaking.sol";
import "../chainlink/interfaces/AggregatorV3Interface.sol";
import "../lzApp/LzApp.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract StargateFeeLibraryV07 is LzApp, IStargateFeeLibrary {
using SafeMath for uint256;
uint256 public constant DENOMINATOR = 1e18;
uint256 public constant DELTA_1 = 6000 * 1e14;
uint256 public constant DELTA_2 = 500 * 1e14;
uint256 public constant LAMBDA_1 = 40 * 1e14;
uint256 public constant LAMBDA_2 = 9960 * 1e14;
uint256 public constant LP_FEE = 1 * 1e14;
uint256 public constant PROTOCOL_FEE = 9 * 1e14;
uint256 public constant PROTOCOL_FEE_FOR_SAME_TOKEN = 5 * 1e14;
uint256 public constant EQ_REWARD_THRESHOLD = 6 * 1e14;
uint256 public constant PROTOCOL_SUBSIDY = 3 * 1e13;
uint8 public constant PRICE_SHARED_DECIMALS = 8;
uint256 public constant ONE_BPS_PRICE_CHANGE_THRESHOLD = 1 * 1e14;
uint256 public constant PRICE_DRIFT_THRESHOLD = 10 * 1e14;
uint256 public constant PRICE_DEPEG_THRESHOLD = 150 * 1e14;
mapping(address => bool) public whitelist;
mapping(uint256 => uint256) public poolIdToLpId;
Factory public immutable factory;
mapping(uint256 => address) public poolIdToPriceFeed;
mapping(uint256 => mapping(uint256 => uint16[])) internal poolPairToRemoteChainIds;
mapping(uint256 => uint256) public poolIdToPriceSD;
mapping(uint16 => bytes) public defaultAdapterParams;
mapping(uint256 => address) public stargatePoolIdToLPStaking;
enum PriceDeviationState {
Normal,
Drift,
Depeg
}
event PriceUpdated(uint256 indexed poolId, uint256 priceSD);
modifier notSamePool(uint256 _poolId1, uint256 _poolId2) {
require(_poolId1 != _poolId2, "FeeLibrary: _poolId1 == _poolId2");
_;
}
constructor(
address _factory,
address _endpoint
) LzApp(_endpoint) {
require(_factory != address(0x0), "FeeLibrary: Factory cannot be 0x0");
require(_endpoint != address(0x0), "FeeLibrary: Endpoint cannot be 0x0");
factory = Factory(_factory);
}
function whiteList(address _from, bool _whiteListed) external onlyOwner {
whitelist[_from] = _whiteListed;
}
function setPoolToLpId(uint256 _poolId, uint256 _lpId) external onlyOwner {
poolIdToLpId[_poolId] = _lpId;
}
function setTokenPriceFeed(uint256 _poolId, address _priceFeedAddress) external onlyOwner {
poolIdToPriceFeed[_poolId] = _priceFeedAddress;
}
function setStargatePoolIdToLPStakingAddress(uint256 _poolId, address _lpStaking) external onlyOwner {
stargatePoolIdToLPStaking[_poolId] = _lpStaking;
}
function initTokenPrice(uint256 _poolId, uint256 _priceSD) external onlyOwner {
poolIdToPriceSD[_poolId] = _priceSD;
emit PriceUpdated(_poolId, _priceSD);
}
function setRemoteChains(
uint256 _poolId1,
uint256 _poolId2,
uint16[] calldata _remoteChainIds
) external onlyOwner notSamePool(_poolId1, _poolId2) {
if (_poolId1 < _poolId2) {
poolPairToRemoteChainIds[_poolId1][_poolId2] = _remoteChainIds;
} else {
poolPairToRemoteChainIds[_poolId2][_poolId1] = _remoteChainIds;
}
}
function setDefaultAdapterParams(uint16 _remoteChainId, bytes calldata _adapterParams) external onlyOwner {
defaultAdapterParams[_remoteChainId] = _adapterParams;
}
function renounceOwnership() public override onlyOwner {}
function updateTokenPrices(uint256 _poolId1, uint256 _poolId2) external payable notSamePool(_poolId1, _poolId2) {
uint256 newPrice1 = _getLatestPriceSDFromPriceFeed(_poolId1);
uint256 newPrice2 = _getLatestPriceSDFromPriceFeed(_poolId2);
poolIdToPriceSD[_poolId1] = newPrice1;
poolIdToPriceSD[_poolId2] = newPrice2;
emit PriceUpdated(_poolId1, newPrice1);
emit PriceUpdated(_poolId2, newPrice2);
uint16[] memory remoteChainIds = getRemoteChains(_poolId1, _poolId2);
require(remoteChainIds.length > 0, "FeeLibrary: invalid pool pair");
bytes memory payload = abi.encode(_poolId1, newPrice1, _poolId2, newPrice2);
for (uint256 i = 0; i < remoteChainIds.length; i++) {
uint16 remoteChainId = remoteChainIds[i];
address refundAddress = i == remoteChainIds.length - 1? msg.sender : address(this);
_lzSend(remoteChainId, payload, payable(refundAddress), address(0), defaultAdapterParams[remoteChainId], address(this).balance);
}
}
function getFees(
uint256 _srcPoolId,
uint256 _dstPoolId,
uint16 _dstChainId,
address _from,
uint256 _amountSD
) external view override returns (Pool.SwapObj memory s) {
bool whitelisted = whitelist[_from];
s.eqReward = getEqReward(_srcPoolId, _amountSD, whitelisted);
bool hasEqReward = s.eqReward > 0;
uint256 protocolSubsidy;
(s.eqFee, protocolSubsidy) = getEquilibriumFee(_srcPoolId, _dstPoolId, _dstChainId, _amountSD, whitelisted, hasEqReward);
(s.protocolFee, s.lpFee) = getProtocolAndLpFee(_srcPoolId, _dstPoolId, _dstChainId, _amountSD, protocolSubsidy, whitelisted);
if (!whitelisted) {
uint256 rewardCap = s.protocolFee.add(s.lpFee);
if (s.eqReward > rewardCap) {
uint256 diff = s.eqReward.sub(rewardCap);
s.protocolFee = s.protocolFee.add(diff);
}
}
uint256 driftFee = getDriftFee(_srcPoolId, _dstPoolId, _amountSD, whitelisted);
s.protocolFee = s.protocolFee.add(driftFee);
if (_amountSD < s.lpFee.add(s.eqFee).add(s.protocolFee)) {
s.protocolFee = _amountSD.sub(s.lpFee).sub(s.eqFee);
}
return s;
}
function quoteFeeForPriceUpdate(uint256 _poolId1, uint256 _poolId2) external view notSamePool(_poolId1, _poolId2) returns (uint256) {
uint256 total = 0;
uint16[] memory remoteChainIds = getRemoteChains(_poolId1, _poolId2);
require(remoteChainIds.length > 0, "FeeLibrary: invalid pool pair");
bytes memory payload = abi.encode(_poolId1, uint256(0), _poolId2, uint256(0));
for (uint256 i = 0; i < remoteChainIds.length; i++) {
uint16 remoteChainId = remoteChainIds[i];
(uint256 fee, ) = lzEndpoint.estimateFees(remoteChainId, address(this), payload, false, defaultAdapterParams[remoteChainId]);
total = total.add(fee);
}
return total;
}
function shouldCallUpdateTokenPrices(uint256 _poolId1, uint256 _poolId2) external view notSamePool(_poolId1, _poolId2) returns (bool) {
uint256 currentPriceSD1 = poolIdToPriceSD[_poolId1];
uint256 currentPriceSD2 = poolIdToPriceSD[_poolId2];
(PriceDeviationState currentState, uint256 currentDiff, bool currentLt) = _getPriceDiffAndDeviationState(currentPriceSD1, currentPriceSD2);
uint256 newPriceSD1 = _getLatestPriceSDFromPriceFeed(_poolId1);
uint256 newPriceSD2 = _getLatestPriceSDFromPriceFeed(_poolId2);
(PriceDeviationState newState, uint256 newDiff, bool newLt) = _getPriceDiffAndDeviationState(newPriceSD1, newPriceSD2);
if (currentState != newState) {
return true;
}
if (newState == PriceDeviationState.Normal) {
return false;
} else if (currentLt != newLt) {
return true;
} else if (newState == PriceDeviationState.Depeg) {
return false;
}
uint256 diffDelta = newDiff > currentDiff ? newDiff.sub(currentDiff) : currentDiff.sub(newDiff);
return diffDelta >= ONE_BPS_PRICE_CHANGE_THRESHOLD;
}
function getEqReward(
uint256 _srcPoolId,
uint256 _amountSD,
bool _whitelisted
) public view returns (uint256) {
Pool pool = factory.getPool(_srcPoolId);
uint256 currentAssetSD = _getPoolBalanceSD(pool);
uint256 lpAsset = pool.totalLiquidity();
uint256 rewardPoolSize = pool.eqFeePool();
if (lpAsset <= currentAssetSD) {
return 0;
}
uint256 poolDeficit = lpAsset.sub(currentAssetSD);
uint256 rate = rewardPoolSize.mul(DENOMINATOR).div(poolDeficit);
if (rate <= EQ_REWARD_THRESHOLD && !_whitelisted) {
return 0;
}
uint256 eqReward = _amountSD.mul(rate).div(DENOMINATOR);
eqReward = eqReward > rewardPoolSize ? rewardPoolSize : eqReward;
return eqReward;
}
function getEquilibriumFee(
uint256 srcPoolId,
uint256 dstPoolId,
uint16 dstChainId,
uint256 amountSD,
bool whitelisted,
bool hasEqReward
) public view returns (uint256, uint256) {
if (whitelisted) {
return (0, 0);
}
Pool.ChainPath memory chainPath = factory.getPool(srcPoolId).getChainPath(dstChainId, dstPoolId);
uint256 idealBalance = chainPath.idealBalance;
uint256 beforeBalance = chainPath.balance;
require(beforeBalance >= amountSD, "FeeLibrary: not enough balance");
uint256 afterBalance = beforeBalance.sub(amountSD);
uint256 safeZoneMax = idealBalance.mul(DELTA_1).div(DENOMINATOR);
uint256 safeZoneMin = idealBalance.mul(DELTA_2).div(DENOMINATOR);
uint256 eqFee = 0;
uint256 protocolSubsidy = 0;
uint256 amountSD_ = amountSD;
if (afterBalance >= safeZoneMax) {
eqFee = amountSD_.mul(PROTOCOL_SUBSIDY).div(DENOMINATOR);
if (!hasEqReward) {
protocolSubsidy = eqFee;
}
} else if (afterBalance >= safeZoneMin) {
uint256 proxyBeforeBalance = beforeBalance < safeZoneMax ? beforeBalance : safeZoneMax;
eqFee = _getTrapezoidArea(LAMBDA_1, 0, safeZoneMax, safeZoneMin, proxyBeforeBalance, afterBalance);
} else {
if (beforeBalance >= safeZoneMin) {
uint256 proxyBeforeBalance = beforeBalance < safeZoneMax ? beforeBalance : safeZoneMax;
eqFee = eqFee.add(_getTrapezoidArea(LAMBDA_1, 0, safeZoneMax, safeZoneMin, proxyBeforeBalance, safeZoneMin));
eqFee = eqFee.add(_getTrapezoidArea(LAMBDA_2, LAMBDA_1, safeZoneMin, 0, safeZoneMin, afterBalance));
} else {
uint256 beforeBalance_ = beforeBalance;
eqFee = eqFee.add(_getTrapezoidArea(LAMBDA_2, LAMBDA_1, safeZoneMin, 0, beforeBalance_, afterBalance));
}
}
return (eqFee, protocolSubsidy);
}
function getProtocolAndLpFee(
uint256 _srcPoolId,
uint256 _dstPoolId,
uint16,
uint256 _amountSD,
uint256 _protocolSubsidy,
bool _whitelisted
) public view returns (uint256, uint256) {
if (_whitelisted) {
return (0, 0);
}
uint256 protocolFeeBps = _srcPoolId == _dstPoolId ? PROTOCOL_FEE_FOR_SAME_TOKEN : PROTOCOL_FEE;
uint256 amountSD = _amountSD;
uint256 srcPoolId = _srcPoolId;
uint256 protocolFee = amountSD.mul(protocolFeeBps).div(DENOMINATOR).sub(_protocolSubsidy);
uint256 lpFee = amountSD.mul(LP_FEE).div(DENOMINATOR);
address lpStakingAddr = stargatePoolIdToLPStaking[srcPoolId];
if(lpStakingAddr != address(0x0)){
IStargateLPStaking lpStaking = IStargateLPStaking(lpStakingAddr);
(, uint256 allocPoint, , ) = lpStaking.poolInfo(poolIdToLpId[srcPoolId]);
if (allocPoint > 0) {
protocolFee = protocolFee.add(lpFee);
lpFee = 0;
}
}
return (protocolFee, lpFee);
}
function getDriftFee(
uint256 _srcPoolId,
uint256 _dstPoolId,
uint256 _amountSD,
bool _whitelisted
) public view returns (uint256) {
if (_srcPoolId == _dstPoolId) {
return 0;
}
uint256 srcPriceSD = poolIdToPriceSD[_srcPoolId];
uint256 dstPriceSD = poolIdToPriceSD[_dstPoolId];
(PriceDeviationState state, , bool lt) = _getPriceDiffAndDeviationState(srcPriceSD, dstPriceSD);
if (!lt || state == PriceDeviationState.Normal) {
return 0;
}
require(state != PriceDeviationState.Depeg, "FeeLibrary: _srcPoolId depeg");
if (_whitelisted) {
return 0;
}
uint256 amountSDAfterFee = _amountSD.mul(srcPriceSD).div(dstPriceSD);
return _amountSD.sub(amountSDAfterFee);
}
function getRemoteChains(uint256 _poolId1, uint256 _poolId2) public view returns (uint16[] memory) {
if (_poolId1 < _poolId2) {
return poolPairToRemoteChainIds[_poolId1][_poolId2];
} else {
return poolPairToRemoteChainIds[_poolId2][_poolId1];
}
}
function getVersion() external pure override returns (string memory) {
return "7.1.0";
}
function _getTrapezoidArea(
uint256 lambda,
uint256 yOffset,
uint256 xUpperBound,
uint256 xLowerBound,
uint256 xStart,
uint256 xEnd
) internal pure returns (uint256) {
require(xEnd >= xLowerBound && xStart <= xUpperBound, "FeeLibrary: balance out of bound");
uint256 xBoundWidth = xUpperBound.sub(xLowerBound);
uint256 yStart = xUpperBound.sub(xStart).mul(lambda).div(xBoundWidth).add(yOffset);
uint256 yEnd = xUpperBound.sub(xEnd).mul(lambda).div(xBoundWidth).add(yOffset);
uint256 deltaX = xStart.sub(xEnd);
return yStart.add(yEnd).mul(deltaX).div(2).div(DENOMINATOR);
}
function _blockingLzReceive(uint16, bytes memory, uint64, bytes memory _payload) internal override {
(uint256 poolId1, uint256 priceSD1, uint256 poolId2, uint256 priceSD2) = abi.decode(_payload, (uint256, uint256, uint256, uint256));
poolIdToPriceSD[poolId1] = priceSD1;
poolIdToPriceSD[poolId2] = priceSD2;
emit PriceUpdated(poolId1, priceSD1);
emit PriceUpdated(poolId2, priceSD2);
}
function _getLatestPriceSDFromPriceFeed(uint256 _poolId) internal view returns (uint256) {
address priceFeed = poolIdToPriceFeed[_poolId];
require(priceFeed != address(0x0), "FeeLibrary: price feed not set");
uint8 decimals = AggregatorV3Interface(priceFeed).decimals();
(, int256 price, , ,) = AggregatorV3Interface(priceFeed).latestRoundData();
require(price >= 0, "FeeLibrary: price is negative");
return _scalePrice(uint256(price), decimals);
}
function _getPriceDiffAndDeviationState(uint256 _priceSD1, uint256 _priceSD2) internal pure returns (PriceDeviationState, uint256, bool) {
(uint256 diff, bool lt) = _getAbsoluteDiffAsBps(_priceSD1, _priceSD2);
PriceDeviationState state;
if (diff <= PRICE_DRIFT_THRESHOLD) {
state = PriceDeviationState.Normal;
} else if (diff >= PRICE_DEPEG_THRESHOLD) {
state = PriceDeviationState.Depeg;
} else {
state = PriceDeviationState.Drift;
}
return (state, diff, lt);
}
function _scalePrice(uint256 _price, uint8 _decimals) internal pure returns (uint256) {
if (_decimals == PRICE_SHARED_DECIMALS) {
return _price;
}
uint256 rate = _scaleRate(_decimals, PRICE_SHARED_DECIMALS);
return _decimals < PRICE_SHARED_DECIMALS ? _price.mul(rate) : _price.div(rate);
}
function _getAbsoluteDiffAsBps(uint256 _a, uint256 _b) internal pure returns (uint256, bool) {
if (_a > _b) {
return (_a.sub(_b).mul(DENOMINATOR).div(_a), false);
} else if (_a == _b) {
return (0, false);
} else {
return (_b.sub(_a).mul(DENOMINATOR).div(_b), true);
}
}
function _scaleRate(uint8 _decimals, uint8 _sharedDecimals) internal pure returns (uint256) {
uint256 diff = _decimals > _sharedDecimals? _decimals - _sharedDecimals : _sharedDecimals - _decimals;
require(diff <= 20, "FeeLibrary: diff of decimals is too large");
return 10 ** diff;
}
function _getPoolBalanceSD(Pool _pool) internal view returns (uint256) {
return IERC20(_pool.token()).balanceOf(address(_pool)).div(_pool.convertRate());
}
receive() external payable {}
}
{
"compilationTarget": {
"contracts/libraries/StargateFeeLibraryV07.sol": "StargateFeeLibraryV07"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_endpoint","type":"address"}],"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":"poolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceSD","type":"uint256"}],"name":"PriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"_type","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"_minDstGas","type":"uint256"}],"name":"SetMinDstGas","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"precrime","type":"address"}],"name":"SetPrecrime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_path","type":"bytes"}],"name":"SetTrustedRemote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"_remoteAddress","type":"bytes"}],"name":"SetTrustedRemoteAddress","type":"event"},{"inputs":[],"name":"DELTA_1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELTA_2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EQ_REWARD_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LAMBDA_1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LAMBDA_2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LP_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_BPS_PRICE_CHANGE_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_DEPEG_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_DRIFT_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_SHARED_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_FEE_FOR_SAME_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_SUBSIDY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"defaultAdapterParams","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"}],"name":"forceResumeReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"_configType","type":"uint256"}],"name":"getConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"uint256","name":"_amountSD","type":"uint256"},{"internalType":"bool","name":"_whitelisted","type":"bool"}],"name":"getDriftFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_amountSD","type":"uint256"},{"internalType":"bool","name":"_whitelisted","type":"bool"}],"name":"getEqReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"srcPoolId","type":"uint256"},{"internalType":"uint256","name":"dstPoolId","type":"uint256"},{"internalType":"uint16","name":"dstChainId","type":"uint16"},{"internalType":"uint256","name":"amountSD","type":"uint256"},{"internalType":"bool","name":"whitelisted","type":"bool"},{"internalType":"bool","name":"hasEqReward","type":"bool"}],"name":"getEquilibriumFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amountSD","type":"uint256"}],"name":"getFees","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"eqFee","type":"uint256"},{"internalType":"uint256","name":"eqReward","type":"uint256"},{"internalType":"uint256","name":"lpFee","type":"uint256"},{"internalType":"uint256","name":"protocolFee","type":"uint256"},{"internalType":"uint256","name":"lkbRemove","type":"uint256"}],"internalType":"struct Pool.SwapObj","name":"s","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_srcPoolId","type":"uint256"},{"internalType":"uint256","name":"_dstPoolId","type":"uint256"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint256","name":"_amountSD","type":"uint256"},{"internalType":"uint256","name":"_protocolSubsidy","type":"uint256"},{"internalType":"bool","name":"_whitelisted","type":"bool"}],"name":"getProtocolAndLpFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"}],"name":"getRemoteChains","outputs":[{"internalType":"uint16[]","name":"","type":"uint16[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256","name":"_priceSD","type":"uint256"}],"name":"initTokenPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"}],"name":"isTrustedRemote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lzEndpoint","outputs":[{"internalType":"contract ILayerZeroEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"_nonce","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"minDstGasLookup","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolIdToLpId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolIdToPriceFeed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolIdToPriceSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precrime","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"}],"name":"quoteFeeForPriceUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"uint256","name":"_configType","type":"uint256"},{"internalType":"bytes","name":"_config","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"internalType":"bytes","name":"_adapterParams","type":"bytes"}],"name":"setDefaultAdapterParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstChainId","type":"uint16"},{"internalType":"uint16","name":"_packetType","type":"uint16"},{"internalType":"uint256","name":"_minGas","type":"uint256"}],"name":"setMinDstGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"uint256","name":"_lpId","type":"uint256"}],"name":"setPoolToLpId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_precrime","type":"address"}],"name":"setPrecrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"}],"name":"setReceiveVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"},{"internalType":"uint16[]","name":"_remoteChainIds","type":"uint16[]"}],"name":"setRemoteChains","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_version","type":"uint16"}],"name":"setSendVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_lpStaking","type":"address"}],"name":"setStargatePoolIdToLPStakingAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"},{"internalType":"address","name":"_priceFeedAddress","type":"address"}],"name":"setTokenPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_path","type":"bytes"}],"name":"setTrustedRemote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"}],"name":"shouldCallUpdateTokenPrices","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stargatePoolIdToLPStaking","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":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"trustedRemoteLookup","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId1","type":"uint256"},{"internalType":"uint256","name":"_poolId2","type":"uint256"}],"name":"updateTokenPrices","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"bool","name":"_whiteListed","type":"bool"}],"name":"whiteList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]