Source Code
Latest 25 from a total of 1,405 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Referrer | 22599613 | 178 days ago | IN | 0 ETH | 0 | ||||
| Set Referrer | 22599493 | 178 days ago | IN | 0 ETH | 0 | ||||
| Set Referral Cod... | 22118232 | 189 days ago | IN | 0 ETH | 0.00000012 | ||||
| Set Referrer | 21935084 | 193 days ago | IN | 0 ETH | 0.00000009 | ||||
| Set Referrer | 21415501 | 205 days ago | IN | 0 ETH | 0.00000006 | ||||
| Set Referrer | 20212722 | 233 days ago | IN | 0 ETH | 0 | ||||
| Set Referrer | 15139109 | 351 days ago | IN | 0 ETH | 0.00000001 | ||||
| Set Referrer | 15139108 | 351 days ago | IN | 0 ETH | 0.00000003 | ||||
| Set Referrer | 14846802 | 358 days ago | IN | 0 ETH | 0.00000005 | ||||
| Set Referrer | 14817448 | 358 days ago | IN | 0 ETH | 0.00000003 | ||||
| Set Referrer | 14543232 | 365 days ago | IN | 0 ETH | 0.00000001 | ||||
| Set Referrer | 14543229 | 365 days ago | IN | 0 ETH | 0.00000002 | ||||
| Set Referrer | 14291566 | 370 days ago | IN | 0 ETH | 0.00000184 | ||||
| Set Referrer | 14109789 | 375 days ago | IN | 0 ETH | 0.00000693 | ||||
| Set Referrer | 13939484 | 379 days ago | IN | 0 ETH | 0.00000002 | ||||
| Set Referrer | 13396393 | 391 days ago | IN | 0 ETH | 0.00000243 | ||||
| Set Referrer | 12885908 | 403 days ago | IN | 0 ETH | 0.00000028 | ||||
| Set Referrer | 12810407 | 405 days ago | IN | 0 ETH | 0.00000007 | ||||
| Set Referrer | 12810400 | 405 days ago | IN | 0 ETH | 0.00000014 | ||||
| Set Referrer | 12802686 | 405 days ago | IN | 0 ETH | 0.00000004 | ||||
| Set Referrer | 12670890 | 408 days ago | IN | 0 ETH | 0.00000209 | ||||
| Set Referrer | 12670888 | 408 days ago | IN | 0 ETH | 0.0000021 | ||||
| Set Referrer | 12631906 | 409 days ago | IN | 0 ETH | 0.00000178 | ||||
| Set Referrer | 12624921 | 409 days ago | IN | 0 ETH | 0.00000311 | ||||
| Set Referrer | 12520744 | 411 days ago | IN | 0 ETH | 0.00000208 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SummitReferrals
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 999 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./interface/ISummitReferrals.sol";
import "./interface/ISummitPoints.sol";
import "./interface/IBlast.sol";
import "./lib/Maintainable.sol";
// | Level | Custom Benefit | Reward | Self Volume Required | Referred Volume Required | Referral Num Required |
// | --- | --- | --- | --- | --- | --- |
// | Wood | | 0 | 0 | 0 | 0 |
// | Bronze | Can refer | 2% | 100 | 0 | 0 |
// | Silver | | 3% | 1000 | 10000 | 3 |
// | Gold | | 5% | 2000 | 25000 | 5 |
// | Platinum | | 7% | 5000 | 100000 | 10 |
// | Noble | | 10% | 25000 | 1000000 | 25 |
contract SummitReferrals is Maintainable, ISummitReferrals {
using SafeMath for uint256;
address public SUMMIT_POINTS;
// Level requirements
uint256 public levelCount = 6;
mapping(uint256 => uint256) public LEVEL_REF_VOLUME_REQ; // = [0, 0, 10000e18, 25000e18, 100000e18, 1000000e18];
mapping(uint256 => uint256) public LEVEL_SELF_VOLUME_REQ; // = [0, 100e18, 1000e18, 2000e18, 5000e18, 25000e18];
mapping(uint256 => uint256) public LEVEL_REFS_REQ; // = [0, 0, 3, 5, 10, 25];
mapping(uint256 => uint256) public LEVEL_MULT_REWARD; // = [0, 200, 400, 500, 700, 1500];
uint256 public BONUS_FOR_BEING_REFERRED = 200;
mapping(address => address) public REFERRER;
mapping(address => uint256) public REF_COUNT;
mapping(address => uint8) public REF_BOOST_LEVEL;
mapping(string => address) public REF_CODE;
mapping(address => string) public REF_CODE_INV;
error InvalidCode();
error AlreadySetCode();
error AlreadyInitialized();
error MissingReferral();
error AlreadyReferredByUser();
error SelfReferral();
error ReciprocalReferral();
error LengthMismatch();
error CodeNotAvailable();
error MustBeAtLeastBronze();
error InvalidLevel();
constructor() {
uint256[6] memory refVolumeReq = [uint256(0), 0, 10000e18, 25000e18, 100000e18, 1000000e18];
uint256[6] memory selfVolumeReq = [uint256(0), 100e18, 1000e18, 2000e18, 5000e18, 25000e18];
uint256[6] memory refsReq = [uint256(0), 0, 3, 5, 10, 25];
uint256[6] memory multReward = [uint256(0), 200, 400, 500, 700, 1500];
for (uint256 i = 0; i < levelCount; i++) {
LEVEL_REF_VOLUME_REQ[i] = refVolumeReq[i];
LEVEL_SELF_VOLUME_REQ[i] = selfVolumeReq[i];
LEVEL_REFS_REQ[i] = refsReq[i];
LEVEL_MULT_REWARD[i] = multReward[i];
}
}
bool public initialized = false;
address public governor;
function initialize(address _governor) public onlyMaintainer {
if (initialized) revert AlreadyInitialized();
initialized = true;
IBlast blast = IBlast(0x4300000000000000000000000000000000000002);
blast.configureClaimableGas();
blast.configureGovernor(_governor);
governor = _governor;
}
function setPointsContract(address _pointsContract) override public onlyMaintainer {
emit UpdatedPointsContract(_pointsContract);
SUMMIT_POINTS = _pointsContract;
}
function stringEquals(string memory s1, string memory s2) internal pure returns(bool) {
return keccak256(abi.encode(s1)) == keccak256(abi.encode(s2));
}
function setReferrer(address _referrer, string memory _code) override public {
// Get referrer from code or argument
address referrer = _referrer == address(0) ? REF_CODE[_code] : _referrer;
// Checks
if (referrer == address(0)) revert MissingReferral();
if (referrer == msg.sender) revert SelfReferral();
if (referrer == REFERRER[msg.sender]) revert AlreadyReferredByUser();
if (REFERRER[referrer] == msg.sender) revert ReciprocalReferral();
if (REFERRER[REFERRER[referrer]] == msg.sender) revert ReciprocalReferral();
// Validate referrer is at least bronze level
if (getReferrerLevel(referrer) == 0) revert MustBeAtLeastBronze();
// Remove from prev referrer count
if (REFERRER[msg.sender] != address(0) && REF_COUNT[REFERRER[msg.sender]] >= 1) {
REF_COUNT[REFERRER[msg.sender]] -= 1;
}
REFERRER[msg.sender] = referrer;
REF_COUNT[referrer] += 1;
emit UpdatedReferrer(msg.sender, referrer);
}
function setReferralCode(string memory _code) override public {
if(bytes(_code).length < 3 || bytes(_code).length > 15) revert InvalidCode();
// Validate user doesnt already have code
if (bytes(REF_CODE_INV[msg.sender]).length != 0) revert AlreadySetCode();
// Validate referrer is at least bronze level
if (getReferrerLevel(msg.sender) == 0) revert MustBeAtLeastBronze();
// If code is already being used
if (REF_CODE[_code] != address(0)) revert CodeNotAvailable();
REF_CODE[REF_CODE_INV[msg.sender]] = address(0);
REF_CODE_INV[msg.sender] = _code;
REF_CODE[_code] = msg.sender;
emit UpdatedReferralCode(msg.sender, msg.sender, _code);
}
function maintainerSetReferralCode(address _add, string memory _code) override public onlyMaintainer {
// If code is already being used
if (REF_CODE[_code] != address(0)) revert CodeNotAvailable();
REF_CODE[REF_CODE_INV[_add]] = address(0);
REF_CODE_INV[_add] = _code;
REF_CODE[_code] = _add;
emit UpdatedReferralCode(msg.sender, _add, _code);
}
function boostReferrer(address _referrer, uint8 _boostLevel) override public onlyMaintainer {
REF_BOOST_LEVEL[_referrer] = _boostLevel;
emit BoostedReferrer(_referrer, _boostLevel);
}
function boostReferrers(address[] memory _referrers, uint8[] memory _levels) override public onlyMaintainer {
if (_referrers.length != _levels.length) revert LengthMismatch();
for (uint256 i = 0; i < _referrers.length; i++) {
if (REF_BOOST_LEVEL[_referrers[i]] != _levels[i]) {
REF_BOOST_LEVEL[_referrers[i]] = _levels[i];
}
}
emit BoostedReferrers(_referrers, _levels);
}
function setLevelData(uint256[] memory _refVolumeReq, uint256[] memory _selfVolumeReq, uint256[] memory _refsReq, uint256[] memory _multReward, uint256 _hasReferrerBonusMult) override public onlyMaintainer {
if (_refVolumeReq.length != _selfVolumeReq.length || _refVolumeReq.length != _refsReq.length || _refVolumeReq.length != _multReward.length) revert LengthMismatch();
uint256 newLength = _refVolumeReq.length;
for (uint256 i = 0; i < newLength; i++) {
LEVEL_REF_VOLUME_REQ[i] = _refVolumeReq[i];
LEVEL_SELF_VOLUME_REQ[i] = _selfVolumeReq[i];
LEVEL_REFS_REQ[i] = _refsReq[i];
LEVEL_MULT_REWARD[i] = _multReward[i];
}
levelCount = newLength;
BONUS_FOR_BEING_REFERRED = _hasReferrerBonusMult;
emit UpdatedLevelData(_refVolumeReq, _selfVolumeReq, _refsReq, _multReward, _hasReferrerBonusMult);
}
function getReferrer(address _add) override public view returns (address) {
return REFERRER[_add];
}
function getReferrerCode(address _add) override public view returns (string memory) {
return REF_CODE_INV[REFERRER[_add]];
}
function getReferrerLevelWithoutBoost(address _add) override public view returns (uint8) {
if (SUMMIT_POINTS == address(0)) return 0;
(uint256 _selfVolume, uint256 _refVolume,) = ISummitPoints(SUMMIT_POINTS).getVolume(_add);
for (uint8 i = 0; i < levelCount; i++) {
if (_selfVolume < LEVEL_SELF_VOLUME_REQ[i + 1]) return i;
if (_refVolume < LEVEL_REF_VOLUME_REQ[i + 1]) return i;
if (REF_COUNT[_add] < LEVEL_REFS_REQ[i + 1]) return i;
}
return uint8(levelCount);
}
function getReferrerLevel(address _add) override public view returns (uint8) {
if (REF_BOOST_LEVEL[_add] > 0) {
return REF_BOOST_LEVEL[_add] > (levelCount - 1) ? uint8(levelCount - 1) : REF_BOOST_LEVEL[_add];
}
return getReferrerLevelWithoutBoost(_add);
}
function getLevelRequirements(uint8 _level) override public view returns (uint256 selfVolume, uint256 refVolume, uint256 refsCount) {
if (_level >= levelCount) revert InvalidLevel();
return (
LEVEL_SELF_VOLUME_REQ[_level],
LEVEL_REF_VOLUME_REQ[_level],
LEVEL_REFS_REQ[_level]
);
}
function getUserNextLevelRequirements(address _add) override public view returns (uint256 selfVolume, uint256 refVolume, uint256 refsCount) {
uint8 nextLevel = getReferrerLevelWithoutBoost(_add) + 1;
uint8 level = nextLevel >= (levelCount - 1) ? uint8(levelCount - 1) : nextLevel;
return getLevelRequirements(level);
}
function getRefsCount(address _add) override public view returns (uint256) {
return REF_COUNT[_add];
}
function getRefVolumeBonusMultiplier(address _add) override public view returns (uint256) {
return LEVEL_MULT_REWARD[getReferrerLevel(_add)];
}
function getSelfVolumeMultiplier(address _add) override public view returns (uint256) {
return 10000 + (REFERRER[_add] != address(0) ? BONUS_FOR_BEING_REFERRED : 0);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ISAVAX.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
interface IwAVAX {
function withdraw(uint256) external;
}
/**
* @notice wAVAX -> sAVAX
**/
contract SAvaxAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address public constant SAVAX = 0x2b2C81e08f1Af8835a78Bb2A90AE924ACE0eA4bE;
address public constant WAVAX = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7;
constructor(uint256 _swapGasEstimate) SummitAdapter("SAvaxAdapter", _swapGasEstimate) {
_setAllowances();
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_tokenIn == WAVAX && _tokenOut == SAVAX && !ISAVAX(SAVAX).mintingPaused() && !_exceedsCap(_amountIn)) {
amountOut = ISAVAX(SAVAX).getSharesByPooledAvax(_amountIn);
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address,
address _tokenOut,
address _to
) internal override {
IwAVAX(WAVAX).withdraw(_amountIn);
uint256 shares = ISAVAX(SAVAX).submit{ value: _amountIn }();
require(shares >= _amountOut, "SummitAdapter: Amount-out too low");
_returnTo(_tokenOut, shares, _to);
}
function _exceedsCap(uint256 _amountIn) internal view returns (bool) {
uint256 newBal = ISAVAX(SAVAX).totalPooledAvax() + _amountIn; // Assume U256::max won't be reached
return newBal > ISAVAX(SAVAX).totalPooledAvaxCap();
}
function _setAllowances() internal {
IERC20(WAVAX).safeApprove(WAVAX, UINT_MAX);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "./UniswapV3AdapterBase.sol";
contract AgniAdapter is UniswapV3AdapterBase {
constructor(
string memory _name,
uint256 _swapGasEstimate,
uint256 _quoterGasLimit,
address _quoter,
address _factory,
uint24[] memory _defaultFees
) UniswapV3AdapterBase(_name, _swapGasEstimate, _quoterGasLimit, _quoter, _factory, _defaultFees) {
}
function agniSwapCallback (
int256 amount0Delta,
int256 amount1Delta,
bytes calldata
) external {
if (amount0Delta > 0) {
IERC20(IUniV3Pool(msg.sender).token0()).transfer(msg.sender, uint256(amount0Delta));
} else {
IERC20(IUniV3Pool(msg.sender).token1()).transfer(msg.sender, uint256(amount1Delta));
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "./UniswapV3likeAdapter.sol";
interface IAlgebraFactory {
function poolByPair(address, address) external view returns (address);
}
contract AlgebraAdapter is UniswapV3likeAdapter {
using SafeERC20 for IERC20;
address immutable FACTORY;
constructor(
string memory _name,
uint256 _swapGasEstimate,
uint256 _quoterGasLimit,
address _quoter,
address _factory
) UniswapV3likeAdapter(_name, _swapGasEstimate, _quoter, _quoterGasLimit) {
FACTORY = _factory;
}
function getBestPool(
address token0,
address token1
) internal view override returns (address mostLiquid) {
return IAlgebraFactory(FACTORY).poolByPair(token0, token1);
}
function algebraSwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata
) external {
if (amount0Delta > 0) {
IERC20(IUniV3Pool(msg.sender).token0()).transfer(msg.sender, uint256(amount0Delta));
} else {
IERC20(IUniV3Pool(msg.sender).token1()).transfer(msg.sender, uint256(amount1Delta));
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IStabilityFund.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract ArableSFAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address public vault;
mapping(address => uint256) public tokenDecimals;
constructor(
string memory _name,
address _vault,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
vault = _vault;
setPoolTokens();
}
function setPoolTokens() public {
uint256 whitelistedTknsLen = IStabilityFund(vault).getStableTokensCount();
for (uint256 i = 0; i < whitelistedTknsLen; i++) {
address token = IStabilityFund(vault).getStableTokens()[i];
tokenDecimals[token] = IERC20(token).decimals();
uint256 allowance = IERC20(token).allowance(address(this), vault);
if (allowance < UINT_MAX) {
IERC20(token).safeApprove(vault, UINT_MAX);
}
}
}
function adjustForDecimals(
uint256 _amount,
address _tokenDiv,
address _tokenMul
) internal view returns (uint256) {
uint256 decimalsDiv = tokenDecimals[_tokenDiv];
uint256 decimalsMul = tokenDecimals[_tokenMul];
return (_amount * 10**decimalsMul) / 10**decimalsDiv;
}
function hasVaultEnoughBal(address _token, uint256 _amount) private view returns (bool) {
return IERC20(_token).balanceOf(vault) >= _amount;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (
_amountIn == 0 ||
_tokenIn == _tokenOut ||
!IStabilityFund(vault).isStableToken(_tokenIn) ||
!IStabilityFund(vault).isStableToken(_tokenOut) ||
IStabilityFund(vault).isTokenDisabled(_tokenIn) ||
IStabilityFund(vault).isTokenDisabled(_tokenOut) ||
!IStabilityFund(vault).swapEnabled()
) {
return 0;
}
uint256 amountOut = adjustForDecimals(_amountIn, _tokenIn, _tokenOut);
uint256 swapFee = IStabilityFund(vault).swapFee();
uint256 swapFeeDivisor = 1 ether;
uint256 feeAmount = (amountOut * swapFee) / swapFeeDivisor;
uint256 amountOutAfterFees = amountOut - feeAmount;
if (!hasVaultEnoughBal(_tokenOut, amountOutAfterFees)) {
return 0;
}
return amountOutAfterFees;
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
IStabilityFund(vault).swap(_tokenIn, _amountIn, _tokenOut);
// Confidently transfer amount-out
_returnTo(_tokenOut, _amountOut, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// Supports Balancerlike pools
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../SummitAdapter.sol";
import "../interface/IVault.sol";
import "../interface/IBasePool.sol";
import "../interface/IMinimalSwapInfoPool.sol";
contract BalancerV2Adapter is SummitAdapter {
using SafeERC20 for IERC20;
address public vault;
mapping(address => mapping(address => uint128)) internal poolToTokenIndex;
mapping(address => mapping(address => address[])) internal tokensToPools;
constructor(
string memory _name,
address _vault,
address[] memory _pools,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
vault = _vault;
addPools(_pools);
}
function addPools(address[] memory _pools) public onlyMaintainer {
for (uint128 i = 0; i < _pools.length; i++) {
address pool = _pools[i];
bytes32 poolId = IBasePool(pool).getPoolId();
(IERC20[] memory tokens, , ) = IVault(vault).getPoolTokens(poolId);
for (uint128 j = 0; j < tokens.length; j++) {
address token = address(tokens[j]);
poolToTokenIndex[pool][token] = j;
for (uint128 k = 0; k < tokens.length; k++) {
if (j != k) {
tokensToPools[token][address(tokens[k])].push(pool);
_approveIfNeeded(token, UINT_MAX);
}
}
}
}
}
function removePools(address[] memory _pools) public onlyMaintainer {
for (uint256 i = 0; i < _pools.length; i++) {
address pool = _pools[i];
bytes32 poolId = IBasePool(pool).getPoolId();
(IERC20[] memory tokens, , ) = IVault(vault).getPoolTokens(poolId);
for (uint128 j = 0; j < tokens.length; j++) {
address token = address(tokens[j]);
for (uint128 k = 0; k < tokens.length; k++) {
if (j != k) {
address[] memory currentPools = tokensToPools[token][address(tokens[k])];
for (uint128 l = 0; l < currentPools.length; l++) {
if (currentPools[l] == pool) {
delete currentPools[l];
}
}
tokensToPools[token][address(tokens[k])] = currentPools;
}
}
}
}
}
function getPools(address tokenIn, address tokenOut) public view returns (address[] memory) {
return tokensToPools[tokenIn][tokenOut];
}
function _approveIfNeeded(address _tokenIn, uint256 _amount) internal {
uint256 allowance = IERC20(_tokenIn).allowance(address(this), vault);
if (allowance < _amount) {
IERC20(_tokenIn).safeApprove(vault, _amount);
}
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (_amountIn == 0 || _tokenIn == _tokenOut) {
return 0;
}
address[] memory pools = getPools(_tokenIn, _tokenOut);
if (pools.length == 0) {
return 0;
}
(, uint256 amountOut) = _getBestPoolForSwap(pools, _tokenIn, _tokenOut, _amountIn);
return amountOut;
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
address[] memory pools = getPools(_tokenIn, _tokenOut);
require(pools.length > 0, "No pools for swapping");
(address pool, ) = _getBestPoolForSwap(pools, _tokenIn, _tokenOut, _amountIn);
require(pool != address(0), "Undefined pool");
IVault.SingleSwap memory swap;
swap.poolId = IBasePool(pool).getPoolId();
swap.kind = IVault.SwapKind.GIVEN_IN;
swap.assetIn = _tokenIn;
swap.assetOut = _tokenOut;
swap.amount = _amountIn;
swap.userData = "0x";
IVault.FundManagement memory fund;
fund.sender = address(this);
fund.recipient = payable(to);
fund.fromInternalBalance = false;
fund.toInternalBalance = false;
IVault(vault).swap(swap, fund, _amountOut, block.timestamp);
}
function _getBestPoolForSwap(
address[] memory pools,
address _tokenIn,
address _tokenOut,
uint256 _amountIn
) internal view returns (address bestPool, uint256 amountOut) {
amountOut = 0;
bestPool = address(0);
for (uint128 i; i < pools.length; i++) {
address pool = pools[i];
if (pool == address(0)) {
continue;
}
IPoolSwapStructs.SwapRequest memory request;
request.poolId = IBasePool(pool).getPoolId();
request.kind = IVault.SwapKind.GIVEN_IN;
request.tokenIn = IERC20(_tokenIn);
request.tokenOut = IERC20(_tokenOut);
request.amount = _amountIn;
request.userData = "0x";
uint256 newAmountOut = _getAmountOut(request, pool);
if (newAmountOut > amountOut) {
amountOut = newAmountOut;
bestPool = pool;
}
}
}
function _getAmountOut(IPoolSwapStructs.SwapRequest memory request, address pool)
internal
view
returns (uint256 amountOut)
{
// Based on https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/vault/contracts/Swaps.sol#L275
(, uint256[] memory balances, ) = IVault(vault).getPoolTokens(request.poolId);
uint256 tokenInTotal = balances[poolToTokenIndex[pool][address(request.tokenIn)]];
uint256 tokenOutTotal = balances[poolToTokenIndex[pool][address(request.tokenOut)]];
amountOut = _getAmountOutSafe(request, tokenInTotal, tokenOutTotal, pool);
}
function _getAmountOutSafe(
IPoolSwapStructs.SwapRequest memory request,
uint256 tokenInTotal,
uint256 tokenOutTotal,
address pool
) internal view returns (uint256) {
try IMinimalSwapInfoPool(pool).onSwap(request, tokenInTotal, tokenOutTotal) returns (uint256 amountOut) {
return amountOut;
} catch {}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract BridgeMigrationAdapter is SummitAdapter {
using SafeERC20 for IERC20;
mapping(address => bool) public isNewBridgeToken;
constructor(
address[] memory _newTokens,
address[] memory _oldTokens,
uint256 _swapGasEstimate
) SummitAdapter("BridgeMigrationAdapter", _swapGasEstimate) {
setNewBridgeTokens(_newTokens, _oldTokens);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (isNewBridgeToken[_tokenOut] && IERC20(_tokenOut).swapSupply(_tokenIn) >= _amountIn) amountOut = _amountIn;
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
IERC20(_tokenOut).swap(_tokenIn, _amountIn);
_returnTo(_tokenOut, _amountOut, _to);
}
function setNewBridgeTokens(address[] memory _newTokens, address[] memory _oldTokens) public onlyMaintainer {
require(_newTokens.length == _oldTokens.length, "Needs to be surjective");
for (uint256 i; i < _newTokens.length; i++) {
require(IERC20(_newTokens[i]).swapSupply(_oldTokens[i]) > 0, "Invalid combination");
_approveIfNeeded(_newTokens[i], _oldTokens[i]);
isNewBridgeToken[_newTokens[i]] = true;
}
}
function _approveIfNeeded(address _newToken, address _oldToken) internal {
uint256 allowance = IERC20(_oldToken).allowance(address(this), _newToken);
if (allowance < UINT_MAX) IERC20(_oldToken).safeApprove(_newToken, UINT_MAX);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
interface IFactory {
function getPair(address,address) external view returns (address);
}
interface IPair {
function getAmountOut(uint256, address) external view returns (uint256);
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data,
address referrer
) external;
}
contract CamelotAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address immutable FACTORY;
address referrer;
constructor(
string memory _name,
address _factory,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
FACTORY = _factory;
}
function setReferrer(address _referrer) public onlyMaintainer {
referrer = _referrer;
}
function getQuoteAndPair(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256 amountOut, address pair) {
pair = IFactory(FACTORY).getPair(_tokenIn, _tokenOut);
if (pair != address(0))
amountOut = IPair(pair).getAmountOut(_amountIn, _tokenIn);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_tokenIn != _tokenOut && _amountIn != 0)
(amountOut, ) = getQuoteAndPair(_amountIn, _tokenIn, _tokenOut);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
(uint256 amountOut, address pair) = getQuoteAndPair(_amountIn, _tokenIn, _tokenOut);
require(amountOut >= _amountOut, "Insufficent amount out");
(uint256 amount0Out, uint256 amount1Out) = (_tokenIn < _tokenOut)
? (uint256(0), amountOut)
: (amountOut, uint256(0));
IERC20(_tokenIn).safeTransfer(pair, _amountIn);
IPair(pair).swap(amount0Out, amount1Out, to, new bytes(0), referrer);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// Supports Curve Atricrypto pools and alike
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ICurve1.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract Curve1Adapter is SummitAdapter {
using SafeERC20 for IERC20;
mapping(address => uint256) public tokenIndex;
mapping(address => bool) public isPoolToken;
address public pool;
constructor(
string memory _name,
address _pool,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
pool = _pool;
_setPoolTokens();
}
// Mapping indicator which tokens are included in the pool
function _setPoolTokens() internal {
for (uint256 i = 0; true; ++i) {
try ICurve1(pool).underlying_coins(i) returns (address token) {
_setPoolTokenAllowance(token);
isPoolToken[token] = true;
tokenIndex[token] = i;
} catch {
break;
}
}
}
function _setPoolTokenAllowance(address _token) internal {
IERC20(_token).approve(pool, UINT_MAX);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (_amountIn == 0 || _tokenIn == _tokenOut || !isPoolToken[_tokenIn] || !isPoolToken[_tokenOut]) {
return 0;
}
try ICurve1(pool).get_dy_underlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 amountOut
) {
return _applyError(amountOut);
} catch {
return 0;
}
}
function _applyError(uint256 _amount) internal pure returns (uint256) {
// `calc_token_amount` in base_pool is used in part of the query
// this method does account for deposit fee which causes discrepancy
// between the query result and the actual swap amount by few bps(0-3.2)
// Additionally there is a rounding error (swap and query may calc different amounts)
// Account for above with 4 bps discount
return _amount == 0 ? 0 : (_amount * (1e4 - 4)) / 1e4;
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
ICurve1(pool).exchange_underlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn, _amountOut);
uint256 balThis = IERC20(_tokenOut).balanceOf(address(this));
_returnTo(_tokenOut, balThis, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// Supports Curve AAVE and Ren pool and alike
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ICurve2.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract Curve2Adapter is SummitAdapter {
using SafeERC20 for IERC20;
uint256 constant BPS_DEN = 1e4;
uint256 constant MAX_ERR_BPS = 1;
mapping(address => bool) public isPoolToken;
mapping(address => int128) public tokenIndex;
address public pool;
constructor(
string memory _name,
address _pool,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
pool = _pool;
_setPoolTokens();
}
// Mapping indicator which tokens are included in the pool
function _setPoolTokens() internal {
for (uint256 i = 0; true; i++) {
try ICurve2(pool).underlying_coins(i) returns (address token) {
_setPoolTokenAllowance(token);
isPoolToken[token] = true;
tokenIndex[token] = int128(int256(i));
} catch {
break;
}
}
}
function _setPoolTokenAllowance(address _token) internal {
IERC20(_token).approve(pool, UINT_MAX);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (_amountIn == 0 || _tokenIn == _tokenOut || !isPoolToken[_tokenIn] || !isPoolToken[_tokenOut]) {
return 0;
}
try ICurve2(pool).get_dy_underlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 amountOut
) {
return _applyErr(amountOut);
} catch {
return 0;
}
}
function _applyErr(uint256 x) internal pure returns (uint256) {
return (x * (BPS_DEN - MAX_ERR_BPS)) / BPS_DEN;
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
ICurve2(pool).exchange_underlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn, 0);
uint256 balThis = IERC20(_tokenOut).balanceOf(address(this));
require(balThis >= _amountOut, "Insufficient amount out");
_returnTo(_tokenOut, balThis, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ICurveMeta.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract CurveMetaAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable POOL;
address public immutable COIN;
mapping(address => int128) public tokenIndex;
mapping(address => bool) public isPoolToken;
constructor(
string memory _name,
address _pool,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
POOL = _pool;
COIN = _setPoolTokens(_pool);
}
function _setPoolTokens(address _pool) internal returns (address coin0) {
coin0 = ICurveMeta(_pool).coins(0);
_approveToken(_pool, coin0, 0);
for (uint256 i = 0; true; i++) {
try ICurveMeta(_pool).base_coins(i) returns (address token) {
_approveToken(_pool, token, int128(int256(i)) + 1);
} catch {
break;
}
}
}
function _approveToken(
address _pool,
address _token,
int128 _index
) internal {
IERC20(_token).safeApprove(_pool, UINT_MAX);
tokenIndex[_token] = _index;
isPoolToken[_token] = true;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (
_amountIn == 0 ||
_tokenIn == _tokenOut ||
!((_tokenIn == COIN && isPoolToken[_tokenOut]) || (_tokenOut == COIN && isPoolToken[_tokenIn]))
) {
return 0;
}
try ICurveMeta(POOL).get_dy_underlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 amountOut
) {
// `calc_token_amount` in base_pool is used in part of the query
// this method does account for deposit fee which causes discrepancy
// between the query result and the actual swap amount by few bps(0-3.2)
// Additionally there is a rounding error (swap and query may calc different amounts)
// Account for that with 1 bps discount
return amountOut == 0 ? 0 : (amountOut * (1e4 - 1)) / 1e4;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
ICurveMeta(POOL).exchange_underlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn, _amountOut);
_returnTo(_tokenOut, IERC20(_tokenOut).balanceOf(address(this)), _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
interface IMetaPool {
function get_dy_underlying(
int128,
int128,
uint256
) external view returns (uint256);
function exchange_underlying(
int128,
int128,
uint256,
uint256
) external;
function coins(uint256) external view returns (address);
}
interface IBasePool {
function coins(uint256) external view returns (address);
}
contract CurveMetaV2Adapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable META_COIN;
address public immutable POOL;
mapping(address => int128) public tokenIndex;
mapping(address => bool) public isPoolToken;
constructor(
string memory _name,
address _pool,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
address metaCoin = getMetaCoin(_pool);
approveAndAddTokenToAdapter(_pool, metaCoin, 0);
addUnderlyingTkns(_pool);
META_COIN = metaCoin;
POOL = _pool;
}
function getMetaCoin(address _pool) internal view returns (address) {
return IMetaPool(_pool).coins(0);
}
function initPoolAndReturnMetaTkn(address _pool) internal returns (address coin0) {
coin0 = IMetaPool(_pool).coins(0);
approveAndAddTokenToAdapter(_pool, coin0, 0);
}
function addUnderlyingTkns(address metaPool) internal {
address basePool = IMetaPool(metaPool).coins(1);
for (uint256 i; true; ++i) {
address token = getUnderlyingToken(basePool, i);
if (token == address(0)) break;
approveAndAddTokenToAdapter(metaPool, token, int128(int256(i)) + 1);
}
}
function getUnderlyingToken(address basePool, uint256 i) internal view returns (address) {
try IBasePool(basePool).coins(i) returns (address token) {
return token;
} catch {}
}
function approveAndAddTokenToAdapter(
address _pool,
address _token,
int128 _index
) internal {
IERC20(_token).safeApprove(_pool, UINT_MAX);
tokenIndex[_token] = _index;
isPoolToken[_token] = true;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (!validInputParams(_amountIn, _tokenIn, _tokenOut)) return 0;
// `calc_token_amount` in base_pool is used in part of the query
// this method does account for deposit fee which causes discrepancy
// between the query result and the actual swap amount by few bps(0-3.2)
// Additionally there is a rounding error (swap and query may calc different amounts)
// Account for that with 1 bps discount
uint256 amountOut = safeQuery(_amountIn, _tokenIn, _tokenOut);
return (amountOut * (1e4 - 1)) / 1e4;
}
function safeQuery(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256) {
try IMetaPool(POOL).get_dy_underlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 amountOut
) {
return amountOut;
} catch {
return 0;
}
}
function validInputParams(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (bool) {
return _amountIn != 0 && _tokenIn != _tokenOut && validPath(_tokenIn, _tokenOut);
}
function validPath(address tkn0, address tkn1) internal view returns (bool) {
return (tkn0 == META_COIN && isPoolToken[tkn1]) || (tkn1 == META_COIN && isPoolToken[tkn0]);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
IMetaPool(POOL).exchange_underlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn, _amountOut);
uint256 balThis = IERC20(_tokenOut).balanceOf(address(this));
_returnTo(_tokenOut, balThis, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
interface IMetaPool {
function get_dy_underlying(
int128,
int128,
uint256
) external view returns (uint256);
function exchange_underlying(
int128,
int128,
uint256,
uint256
) external;
function coins(uint256) external view returns (address);
}
interface IBasePool {
function coins(uint256) external view returns (address);
}
contract CurveMetaV3Adapter is SummitAdapter {
using SafeERC20 for IERC20;
mapping(address => mapping(address => int128)) public tokenIndexForPool;
mapping(address => mapping(address => address)) public poolForTokens;
constructor(
string memory _name,
address[] memory _pools,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
setPools(_pools);
}
function getPool(address tkn0, address tkn1) public view returns (address) {
return poolForTokens[tkn0][tkn1];
}
function rmPools(address[] memory _pools) external onlyMaintainer {
for (uint256 i; i < _pools.length; ++i) _rmPool(_pools[i]);
}
function setPools(address[] memory _pools) public onlyMaintainer {
for (uint256 i; i < _pools.length; ++i) _setPool(_pools[i]);
}
function _setPool(address _pool) internal {
(address mToken, address basePool) = getCoins(_pool);
IERC20(mToken).safeApprove(_pool, UINT_MAX);
for (uint256 i; true; ++i) {
address uToken = getUnderlyingToken(basePool, i);
if (uToken == address(0)) break;
_setTokenPair(_pool, mToken, uToken, int128(int256(i)));
}
}
function _rmPool(address _pool) internal {
(address mToken, address basePool) = getCoins(_pool);
for (uint256 i; true; ++i) {
address uToken = getUnderlyingToken(basePool, i);
if (uToken == address(0)) break;
poolForTokens[uToken][mToken] = address(0);
poolForTokens[mToken][uToken] = address(0);
}
}
function getCoins(address _pool) internal view returns (address meta, address base) {
meta = IMetaPool(_pool).coins(0);
base = IMetaPool(_pool).coins(1);
}
function _setTokenPair(
address _pool,
address _metaTkn,
address _uToken,
int128 _index
) internal {
IERC20(_uToken).safeApprove(_pool, UINT_MAX);
tokenIndexForPool[_pool][_uToken] = _index + 1;
poolForTokens[_uToken][_metaTkn] = _pool;
poolForTokens[_metaTkn][_uToken] = _pool;
}
function getUnderlyingToken(address basePool, uint256 i) internal view returns (address) {
try IBasePool(basePool).coins(i) returns (address token) {
return token;
} catch {}
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
address pool = getPool(_tokenIn, _tokenOut);
if (pool == address(0) || _amountIn == 0) return 0;
// `calc_token_amount` in base_pool is used in part of the query
// this method does account for deposit fee which causes discrepancy
// between the query result and the actual swap amount by few bps(0-3.2)
// Additionally there is a rounding error (swap and query may calc different amounts)
// Account for that with 1 bps discount
uint256 amountOut = safeQuery(pool, _amountIn, _tokenIn, _tokenOut);
return (amountOut * (1e4 - 1)) / 1e4;
}
function safeQuery(
address _pool,
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256) {
try
IMetaPool(_pool).get_dy_underlying(
tokenIndexForPool[_pool][_tokenIn],
tokenIndexForPool[_pool][_tokenOut],
_amountIn
)
returns (uint256 amountOut) {
return amountOut;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
address pool = getPool(_tokenIn, _tokenOut);
IMetaPool(pool).exchange_underlying(
tokenIndexForPool[pool][_tokenIn],
tokenIndexForPool[pool][_tokenOut],
_amountIn,
_amountOut
);
uint256 balThis = IERC20(_tokenOut).balanceOf(address(this));
_returnTo(_tokenOut, balThis, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// Supports Curve MIM pool (manually enter base tokens)
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ICurveMeta.sol";
import "../interface/ICurve2.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
interface ICurveSwapper128 {
function exchange_underlying(
address pool,
int128 i,
int128 j,
uint256 dx,
uint256 minDy
) external;
}
contract CurveMetaWithSwapperAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable metaPool;
address public immutable basePool;
address public immutable swapper;
address public immutable metaTkn;
mapping(address => int128) public tokenIndex;
mapping(address => bool) public isPoolToken;
constructor(
string memory _name,
uint256 _swapGasEstimate,
address _metaPool,
address _basePool,
address _swapper
) SummitAdapter(_name, _swapGasEstimate) {
metaTkn = setMetaTkn(_metaPool, _swapper);
metaPool = _metaPool;
basePool = _basePool;
swapper = _swapper;
_setUnderlyingTokens(_basePool, _swapper);
}
// Mapping indicator which tokens are included in the pool
function _setUnderlyingTokens(address _basePool, address _swapper) internal {
for (uint256 i = 0; true; i++) {
try ICurve2(_basePool).underlying_coins(i) returns (address token) {
_setPoolTokenAllowance(token, _swapper);
isPoolToken[token] = true;
tokenIndex[token] = int128(int256(i)) + 1;
} catch {
break;
}
}
}
function setMetaTkn(address _metaPool, address _swapper) internal returns (address _metaTkn) {
_metaTkn = ICurveMeta(_metaPool).coins(0);
_setPoolTokenAllowance(_metaTkn, _swapper);
isPoolToken[_metaTkn] = true;
tokenIndex[_metaTkn] = 0;
}
function _setPoolTokenAllowance(address _token, address _target) internal {
IERC20(_token).approve(_target, UINT_MAX);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (!validInputParams(_amountIn, _tokenIn, _tokenOut)) {
return 0;
}
try ICurveMeta(metaPool).get_dy_underlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 amountOut
) {
// `calc_token_amount` in base_pool is used in part of the query
// this method does account for deposit fee which causes discrepancy
// between the query result and the actual swap amount by few bps(0-3.2)
// Additionally there is a rounding error (swap and query may calc different amounts)
// Account for that with 4 bps discount
return amountOut == 0 ? 0 : (amountOut * (1e4 - 4)) / 1e4;
} catch {
return 0;
}
}
function validInputParams(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (bool) {
return _amountIn != 0 && _tokenIn != _tokenOut && validPath(_tokenIn, _tokenOut);
}
function validPath(address tkn0, address tkn1) internal view returns (bool) {
return (tkn0 == metaTkn && isPoolToken[tkn1]) || (tkn1 == metaTkn && isPoolToken[tkn0]);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
ICurveSwapper128(swapper).exchange_underlying(
metaPool,
tokenIndex[_tokenIn],
tokenIndex[_tokenOut],
_amountIn,
0
);
uint256 balThis = IERC20(_tokenOut).balanceOf(address(this));
require(balThis >= _amountOut, "Insufficient amount-out");
_returnTo(_tokenOut, balThis, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ICurvePlain128.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract CurvePlain128Adapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable POOL;
mapping(address => int128) public tokenIndex;
mapping(address => bool) public isPoolToken;
constructor(
string memory _name,
address _pool,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
POOL = _pool;
_setPoolTokens(_pool);
}
// Mapping indicator which tokens are included in the pool
function _setPoolTokens(address _pool) internal {
for (uint256 i = 0; true; i++) {
try ICurvePlain128(_pool).coins(i) returns (address token) {
_approveToken(_pool, token, int128(int256(i)));
} catch {
break;
}
}
}
function _approveToken(
address _pool,
address _token,
int128 _index
) internal {
IERC20(_token).safeApprove(_pool, UINT_MAX);
tokenIndex[_token] = _index;
isPoolToken[_token] = true;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (!_validArgs(_amountIn, _tokenIn, _tokenOut)) return 0;
uint256 amountOut = _getDySafe(_amountIn, _tokenIn, _tokenOut);
// Account for possible rounding error
return amountOut > 0 ? amountOut - 1 : 0;
}
function _validArgs(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (bool) {
return _amountIn != 0 && _tokenIn != _tokenOut && isPoolToken[_tokenIn] && isPoolToken[_tokenOut];
}
function _getDySafe(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256) {
try ICurvePlain128(POOL).get_dy(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 amountOut
) {
return amountOut;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
ICurvePlain128(POOL).exchange(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn, _amountOut);
// Confidently transfer amount-out
_returnTo(_tokenOut, _amountOut, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ICurvePlain128Native.sol";
import "../interface/IERC20.sol";
import "../interface/IWETH.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract CurvePlain128NativeAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address constant NATIVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address immutable WNATIVE;
address public immutable POOL;
mapping(address => int128) public tokenIndex;
mapping(address => bool) public isPoolToken;
constructor(
string memory _name,
uint256 _swapGasEstimate,
address _pool,
address _wNative
) SummitAdapter(_name, _swapGasEstimate) {
IERC20(_wNative).safeApprove(_wNative, UINT_MAX);
_setPoolTokens(_pool, _wNative);
WNATIVE = _wNative;
POOL = _pool;
}
// Mapping indicator which tokens are included in the pool
function _setPoolTokens(address _pool, address _wNative) internal {
for (uint256 i = 0; true; i++) {
try ICurvePlain128Native(_pool).coins(i) returns (address token) {
_addTokenToPool(_pool, token, int128(int256(i)), _wNative);
} catch {
break;
}
}
}
function _addTokenToPool(
address _pool,
address _token,
int128 _index,
address _wNative
) internal {
if (_token != NATIVE) {
IERC20(_token).safeApprove(_pool, UINT_MAX);
} else {
_token = _wNative;
}
tokenIndex[_token] = _index;
isPoolToken[_token] = true;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (!_validArgs(_amountIn, _tokenIn, _tokenOut)) return 0;
uint256 amountOut = _getDySafe(_amountIn, _tokenIn, _tokenOut);
// Account for possible rounding error
return amountOut > 0 ? amountOut - 1 : 0;
}
function _validArgs(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (bool) {
return _amountIn != 0 &&
_tokenIn != _tokenOut &&
isPoolToken[_tokenIn] &&
isPoolToken[_tokenOut];
}
function _getDySafe(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256) {
try ICurvePlain128Native(POOL).get_dy(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 amountOut
) {
return amountOut;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
uint256 transferVal;
if (_tokenIn == WNATIVE) {
transferVal = _amountIn;
IWETH(WNATIVE).withdraw(_amountIn);
}
uint256 dy = ICurvePlain128Native(POOL).exchange{ value: transferVal }(
tokenIndex[_tokenIn],
tokenIndex[_tokenOut],
_amountIn,
_amountOut
);
if (_tokenOut == WNATIVE) {
IWETH(WNATIVE).deposit{ value: dy }();
}
_returnTo(_tokenOut, dy, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ICurvePlain256.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract CurvePlain256Adapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable POOL;
mapping(address => uint256) public tokenIndex;
mapping(address => bool) public isPoolToken;
constructor(
string memory _name,
address _pool,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
name = _name;
POOL = _pool;
_setPoolTokens(_pool);
setSwapGasEstimate(_swapGasEstimate);
}
function _setPoolTokens(address _pool) internal {
for (uint256 i = 0; true; i++) {
address token = _getCoinByIndexSafe(_pool, i);
if (token == address(0)) break;
_addToken(_pool, token, i);
}
}
function _getCoinByIndexSafe(address _pool, uint256 _index) internal view returns (address token) {
try ICurvePlain256(_pool).coins(_index) returns (address _token) {
token = _token;
} catch {}
}
function _addToken(
address _pool,
address _token,
uint256 _index
) internal {
IERC20(_token).safeApprove(_pool, UINT_MAX);
tokenIndex[_token] = _index;
isPoolToken[_token] = true;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (!_validArgs(_amountIn, _tokenIn, _tokenOut)) return 0;
uint256 amountOut = _getDySafe(_amountIn, _tokenIn, _tokenOut);
// Account for possible rounding error
return amountOut > 0 ? amountOut - 1 : 0;
}
function _validArgs(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (bool) {
return _amountIn != 0 && _tokenIn != _tokenOut && isPoolToken[_tokenIn] && isPoolToken[_tokenOut];
}
function _getDySafe(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256) {
try ICurvePlain256(POOL).get_dy(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 amountOut
) {
return amountOut;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
ICurvePlain256(POOL).exchange(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn, _amountOut);
// Confidently transfer amount-out
_returnTo(_tokenOut, _amountOut, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IDodoV1.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract DodoV1Adapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable HELPER;
mapping(address => mapping(address => address)) tknsToPool; // base > quote > pool
constructor(
string memory _name,
address[] memory _pools,
address _helper,
uint256 _gasEstimate
) SummitAdapter(_name, _gasEstimate) {
_setPools(_pools, true);
HELPER = _helper;
}
function setPools(address[] memory _pools, bool overwrite) external onlyMaintainer {
_setPools(_pools, overwrite);
}
function _rmPools(address[] memory _pools) external onlyMaintainer {
for (uint256 i; i < _pools.length; ++i) {
(address baseTkn, address quoteTkn) = _getTknsForPool(_pools[i]);
tknsToPool[baseTkn][quoteTkn] = address(0);
}
}
function _setPools(address[] memory _pools, bool overwrite) internal {
for (uint256 i; i < _pools.length; ++i) _setPool(_pools[i], overwrite);
}
function _setPool(address _pool, bool overwrite) internal {
(address baseTkn, address quoteTkn) = _getTknsForPool(_pool);
if (!overwrite) _overwriteCheck(baseTkn, quoteTkn, _pool);
_approveTknsForPool(baseTkn, quoteTkn, _pool);
tknsToPool[baseTkn][quoteTkn] = _pool;
}
function _getTknsForPool(address _pool) internal view returns (address baseToken, address quoteToken) {
baseToken = IDodoV1(_pool)._BASE_TOKEN_();
quoteToken = IDodoV1(_pool)._QUOTE_TOKEN_();
}
function _overwriteCheck(
address baseTkn,
address quoteTkn,
address pool
) internal view {
address existingPool = tknsToPool[baseTkn][quoteTkn];
require(existingPool == address(0) || existingPool == pool, "Not allowed to overwrite");
}
function _approveTknsForPool(
address _baseTkn,
address _quoteTkn,
address _pool
) internal {
IERC20(_baseTkn).safeApprove(_pool, UINT_MAX);
IERC20(_quoteTkn).safeApprove(_pool, UINT_MAX);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (_amountIn == 0) return 0;
address pool = tknsToPool[_tokenIn][_tokenOut];
if (pool != address(0)) return IDodoV1(pool).querySellBaseToken(_amountIn);
pool = tknsToPool[_tokenOut][_tokenIn];
if (pool != address(0)) return IDodoHelper(HELPER).querySellQuoteToken(pool, _amountIn);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
address pool = tknsToPool[_tokenIn][_tokenOut];
if (pool != address(0)) IDodoV1(pool).sellBaseToken(_amountIn, _amountOut, "");
pool = tknsToPool[_tokenOut][_tokenIn];
if (pool != address(0)) IDodoV1(pool).buyBaseToken(_amountOut, _amountIn, "");
_returnTo(_tokenOut, _amountOut, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IDodoV2.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract DodoV2Adapter is SummitAdapter {
using SafeERC20 for IERC20;
mapping(address => mapping(address => address)) public tknsToPool; // base > quote > pool
constructor(
string memory _name,
address[] memory _pools,
uint256 _gasEstimate
) SummitAdapter(_name, _gasEstimate) {
_setPools(_pools, true);
}
function setPools(address[] memory _pools, bool overwrite) external onlyMaintainer {
_setPools(_pools, overwrite);
}
function _rmPools(address[] memory _pools) external onlyMaintainer {
for (uint256 i; i < _pools.length; ++i) {
(address baseTkn, address quoteTkn) = _getTknsForPool(_pools[i]);
tknsToPool[baseTkn][quoteTkn] = address(0);
}
}
function _setPools(address[] memory _pools, bool overwrite) internal {
for (uint256 i; i < _pools.length; ++i) _setPool(_pools[i], overwrite);
}
function _setPool(address _pool, bool overwrite) internal {
(address baseTkn, address quoteTkn) = _getTknsForPool(_pool);
if (!overwrite) _overwriteCheck(baseTkn, quoteTkn, _pool);
tknsToPool[baseTkn][quoteTkn] = _pool;
}
function _getTknsForPool(address _pool) internal view returns (address baseToken, address quoteToken) {
baseToken = IDodoV2(_pool)._BASE_TOKEN_();
quoteToken = IDodoV2(_pool)._QUOTE_TOKEN_();
}
function _overwriteCheck(
address baseTkn,
address quoteTkn,
address pool
) internal view {
address existingPool = tknsToPool[baseTkn][quoteTkn];
require(existingPool == address(0) || existingPool == pool, "Not allowed to overwrite");
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 returnAmount) {
if (_amountIn == 0) return 0;
address pool = tknsToPool[_tokenIn][_tokenOut];
if (pool != address(0)) return IDodoV2(pool).querySellBase(address(this), _amountIn);
pool = tknsToPool[_tokenOut][_tokenIn];
if (pool != address(0)) return IDodoV2(pool).querySellQuote(address(this), _amountIn);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
uint256 returned = _dodoSwap(_amountIn, _tokenIn, _tokenOut);
require(returned >= _amountOut, "Insufficient amount-out");
_returnTo(_tokenOut, returned, _to);
}
function _dodoSwap(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal returns (uint256) {
(function(address) external returns (uint256) fn, address pool) = _getPoolAndSwapFn(_tokenIn, _tokenOut);
IERC20(_tokenIn).safeTransfer(pool, _amountIn);
return fn(address(this));
}
function _getPoolAndSwapFn(address _tokenIn, address _tokenOut)
internal
view
returns (function(address) external returns (uint256), address)
{
address pool = tknsToPool[_tokenIn][_tokenOut];
if (pool != address(0)) return (IDodoV2(pool).sellBase, pool);
pool = tknsToPool[_tokenOut][_tokenIn];
if (pool != address(0)) return (IDodoV2(pool).sellQuote, pool);
revert("Token pair not supported");
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IUniswapFactory.sol";
import "../interface/IUniswapPair.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
interface IDxSwapPair is IUniswapPair {
function swapFee() external view returns (uint256);
}
contract DxSwapAdapter is SummitAdapter {
using SafeERC20 for IERC20;
uint256 internal constant FEE_DENOMINATOR = 1e4;
address public immutable FACTORY;
constructor(
string memory _name,
address _factory,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
FACTORY = _factory;
}
function _getAmountOut(
uint256 _amountIn,
uint256 _reserveIn,
uint256 _reserveOut,
uint256 _fee
) internal pure returns (uint256 amountOut) {
uint256 feeCompliment = FEE_DENOMINATOR - _fee;
uint256 amountInWithFee = _amountIn * feeCompliment;
uint256 numerator = amountInWithFee * _reserveOut;
uint256 denominator = _reserveIn * FEE_DENOMINATOR + amountInWithFee;
amountOut = numerator / denominator;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (_tokenIn == _tokenOut || _amountIn == 0) {
return 0;
}
address pair = IUniswapFactory(FACTORY).getPair(_tokenIn, _tokenOut);
if (pair == address(0)) {
return 0;
}
(uint256 r0, uint256 r1, ) = IUniswapPair(pair).getReserves();
(uint256 reserveIn, uint256 reserveOut) = _tokenIn < _tokenOut ? (r0, r1) : (r1, r0);
if (reserveIn > 0 && reserveOut > 0) {
uint256 fee = IDxSwapPair(pair).swapFee();
return _getAmountOut(_amountIn, reserveIn, reserveOut, fee);
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
address pair = IUniswapFactory(FACTORY).getPair(_tokenIn, _tokenOut);
(uint256 amount0Out, uint256 amount1Out) = (_tokenIn < _tokenOut)
? (uint256(0), _amountOut)
: (_amountOut, uint256(0));
IERC20(_tokenIn).safeTransfer(pair, _amountIn);
IUniswapPair(pair).swap(amount0Out, amount1Out, to, new bytes(0));
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "./UniswapV3AdapterBase.sol";
contract FusionAdapter is UniswapV3AdapterBase {
constructor(
string memory _name,
uint256 _swapGasEstimate,
uint256 _quoterGasLimit,
address _quoter,
address _factory,
uint24[] memory _defaultFees
) UniswapV3AdapterBase(_name, _swapGasEstimate, _quoterGasLimit, _quoter, _factory, _defaultFees) {
}
function fusionXV3SwapCallback (
int256 amount0Delta,
int256 amount1Delta,
bytes calldata
) external {
if (amount0Delta > 0) {
IERC20(IUniV3Pool(msg.sender).token0()).transfer(msg.sender, uint256(amount0Delta));
} else {
IERC20(IUniV3Pool(msg.sender).token1()).transfer(msg.sender, uint256(amount1Delta));
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IGeodePortal.sol";
import "../interface/IGeodeWP.sol";
import "../interface/IgAVAX.sol";
import "../interface/IERC20.sol";
import "../interface/IWETH.sol";
import "../SummitAdapter.sol";
contract GeodeWPAdapter is SummitAdapter {
address internal constant WAVAX = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7;
uint256 internal constant gAVAX_DENOMINATOR = 1e18;
uint256 internal constant IGNORABLE_DEBT = 1e18;
uint256 public immutable pooledTknId;
address public immutable portal;
address public immutable gavax;
address public immutable pool;
address public pooledTknInterface;
constructor(
string memory _name,
address _portal,
uint256 _pooledTknId,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
pooledTknInterface = IGeodePortal(_portal).planetCurrentInterface(_pooledTknId);
address _pool = IGeodePortal(_portal).planetWithdrawalPool(_pooledTknId);
address _gavax = IGeodePortal(_portal).gAVAX();
IgAVAX(_gavax).setApprovalForAll(_pool, true);
pooledTknId = _pooledTknId;
portal = _portal;
gavax = _gavax;
pool = _pool;
}
function setInterfaceForPooledTkn(address interfaceAddress) public onlyMaintainer {
require(IgAVAX(gavax).isInterface(interfaceAddress, pooledTknId), "Not valid interface");
pooledTknInterface = interfaceAddress;
}
function setGAvaxAllowance() public onlyMaintainer {
IgAVAX(gavax).setApprovalForAll(pool, true);
}
function revokeGAvaxAllowance() public onlyMaintainer {
IgAVAX(gavax).setApprovalForAll(pool, false);
}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual returns (bytes4) {
return this.onERC1155Received.selector;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_amountIn == 0 || IGeodeWP(pool).paused()) {
amountOut = 0;
} else if (_tokenIn == WAVAX && _tokenOut == pooledTknInterface) {
amountOut = _calcSwapAndMint(_amountIn);
} else if (_tokenOut == WAVAX && _tokenIn == pooledTknInterface) {
amountOut = _calcSwap(1, 0, _amountIn);
}
}
function _calcSwapAndMint(uint256 amountIn) internal view returns (uint256) {
uint256 debt = IGeodeWP(pool).getDebt();
if (debt >= amountIn || _stakingPaused()) {
// If pool is unbalanced and missing avax it's cheaper to swap
return _calcSwap(0, 1, amountIn);
} else {
// Swap debt and mint the rest
uint256 amountOutBought;
if (debt > IGNORABLE_DEBT) {
amountOutBought = _calcSwap(0, 1, debt);
amountIn -= debt;
}
uint256 amountOutMinted = _calcMint(amountIn);
return amountOutBought + amountOutMinted;
}
}
function _stakingPaused() internal view returns (bool) {
return IGeodePortal(portal).isStakingPausedForPool(pooledTknId);
}
function _calcSwap(
uint8 tknInIndex,
uint8 tknOutIndex,
uint256 amountIn
) internal view returns (uint256) {
try IGeodeWP(pool).calculateSwap(tknInIndex, tknOutIndex, amountIn) returns (uint256 amountOut) {
return amountOut;
} catch {
return 0;
}
}
function _calcMint(uint256 amountIn) internal view returns (uint256) {
uint256 price = IgAVAX(gavax).pricePerShare(pooledTknId);
return (amountIn * gAVAX_DENOMINATOR) / price;
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
if (_tokenIn == WAVAX) {
IWETH(WAVAX).withdraw(_amountIn);
if (_stakingPaused()) {
_swapUnderlying(0, 1, _amountIn, _amountOut, _amountIn);
} else {
_geodeStake(_amountIn, _amountOut);
}
} else {
_swapUnderlying(1, 0, _amountIn, _amountOut, 0);
IWETH(WAVAX).deposit{ value: address(this).balance }();
}
uint256 balThis = IERC20(_tokenOut).balanceOf(address(this));
require(balThis >= _amountOut, "Insufficient amount out");
_returnTo(_tokenOut, balThis, _to);
}
function _swapUnderlying(
uint8 _tokenInIndex,
uint8 _tokenOutIndex,
uint256 _amountIn,
uint256 _amountOut,
uint256 _val
) internal {
IGeodeWP(pool).swap{ value: _val }(_tokenInIndex, _tokenOutIndex, _amountIn, _amountOut, block.timestamp);
}
function _geodeStake(uint256 _amountIn, uint256 _amountOut) internal {
IGeodePortal(portal).stake{ value: _amountIn }(pooledTknId, _amountOut, block.timestamp);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IGmxVault.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract GmxAdapter is SummitAdapter {
using SafeERC20 for IERC20;
uint256 public constant BASIS_POINTS_DIVISOR = 1e4;
uint256 public constant PRICE_PRECISION = 1e30;
uint256 public constant USDG_DECIMALS = 18;
address public immutable VAULT;
bool immutable USE_VAULT_UTILS;
address immutable USDG;
mapping(address => bool) public isPoolTkn; // unwanted tkns can be ignored by adapter
mapping(address => uint256) tokenDecimals;
constructor(
string memory _name,
address _vault,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
_setVaultTkns(_vault);
USE_VAULT_UTILS = _vaultHasUtils(_vault);
USDG = IGmxVault(_vault).usdg();
VAULT = _vault;
}
// UTILS \\
function addPoolTkns(address[] calldata _tokens) external onlyMaintainer {
for (uint256 i; i < _tokens.length; ++i) _setToken(_tokens[i]);
}
function rmPoolTkns(address[] calldata _tokens) external onlyMaintainer {
for (uint256 i; i < _tokens.length; ++i) isPoolTkn[_tokens[i]] = false;
}
function _setVaultTkns(address _vault) internal {
uint256 whitelistedTknsLen = IGmxVault(_vault).allWhitelistedTokensLength();
for (uint256 i = 0; i < whitelistedTknsLen; i++) {
address token = IGmxVault(_vault).allWhitelistedTokens(i);
_setToken(token);
}
}
function _setToken(address _token) internal {
tokenDecimals[_token] = IERC20(_token).decimals();
isPoolTkn[_token] = true;
}
function _vaultHasUtils(address _vault) internal view returns (bool) {
try IGmxVault(_vault).vaultUtils() {
return true;
} catch {
return false;
}
}
// QUERY \\
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (_validArgs(_amountIn, _tokenIn, _tokenOut)) return _getAmountOut(_amountIn, _tokenIn, _tokenOut);
}
function _validArgs(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (bool) {
return
_amountIn != 0 &&
_tokenIn != _tokenOut &&
isPoolTkn[_tokenIn] &&
IGmxVault(VAULT).whitelistedTokens(_tokenIn) &&
IGmxVault(VAULT).whitelistedTokens(_tokenOut) &&
IGmxVault(VAULT).isSwapEnabled() &&
_hasVaultEnoughBal(_tokenIn, 1); // Prevents calc problems
}
function _getAmountOut(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256) {
(uint256 amountOut, uint256 usdgAmount) = _getGrossAmountOutAndUsdg(_amountIn, _tokenIn, _tokenOut);
return _calcNetAmountOut(_tokenIn, _tokenOut, amountOut, usdgAmount);
}
function _calcNetAmountOut(
address _tokenIn,
address _tokenOut,
uint256 _amountOut,
uint256 _usdgAmount
) internal view returns (uint256) {
uint256 feeBps = _getFeeBasisPoint(_tokenIn, _tokenOut, _usdgAmount);
uint256 netAmountOut = _amountOutAfterFees(_amountOut, feeBps);
bool withinVaultLimits = _isWithinVaultLimits(_tokenIn, _tokenOut, _usdgAmount, netAmountOut);
if (withinVaultLimits) return netAmountOut;
}
function _getGrossAmountOutAndUsdg(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256 amountOut, uint256 usdgAmount) {
(uint256 priceIn, uint256 priceOut) = _getPrices(_tokenIn, _tokenOut);
amountOut = (_amountIn * priceIn) / priceOut;
amountOut = _adjustForDecimals(amountOut, _tokenIn, _tokenOut);
usdgAmount = _getUsdgAmount(_amountIn, priceIn, _tokenIn);
}
function _getUsdgAmount(
uint256 _amountIn,
uint256 _priceIn,
address _tokenIn
) internal view returns (uint256 usdgAmount) {
usdgAmount = (_amountIn * _priceIn) / PRICE_PRECISION;
usdgAmount = _adjustForDecimals(usdgAmount, _tokenIn, USDG);
}
function _amountOutAfterFees(uint256 _amountOut, uint256 _feeBasisPoints) internal pure returns (uint256) {
return (_amountOut * (BASIS_POINTS_DIVISOR - _feeBasisPoints)) / BASIS_POINTS_DIVISOR;
}
function _adjustForDecimals(
uint256 _amount,
address _tokenDiv,
address _tokenMul
) internal view returns (uint256) {
uint256 decimalsDiv = _tokenDiv == USDG ? USDG_DECIMALS : tokenDecimals[_tokenDiv];
uint256 decimalsMul = _tokenMul == USDG ? USDG_DECIMALS : tokenDecimals[_tokenMul];
return (_amount * 10**decimalsMul) / 10**decimalsDiv;
}
function _getPrices(address _tokenIn, address _tokenOut) internal view returns (uint256 priceIn, uint256 priceOut) {
IGmxVaultPriceFeed priceFeed = IGmxVault(VAULT).priceFeed();
priceIn = priceFeed.getPrice(_tokenIn, false, true, true);
priceOut = priceFeed.getPrice(_tokenOut, true, true, true);
}
function _hasVaultEnoughBal(address _token, uint256 _amount) private view returns (bool) {
return IERC20(_token).balanceOf(VAULT) >= _amount;
}
function _isWithinVaultLimits(
address _tokenIn,
address _tokenOut,
uint256 _amountInUsdg,
uint256 _amountOut
) private view returns (bool) {
uint256 poolBalTknOut = IGmxVault(VAULT).poolAmounts(_tokenOut);
if (poolBalTknOut < _amountOut) return false;
uint256 newPoolBalTknOut = poolBalTknOut - _amountOut;
return
!reservedAmountExceeded(newPoolBalTknOut, _tokenOut) &&
!bufferAmountExceeded(newPoolBalTknOut, _tokenOut) &&
!maxDebtExceeded(_amountInUsdg, _tokenIn);
}
function reservedAmountExceeded(uint256 _newPoolBalTknOut, address _tokenOut) internal view returns (bool) {
uint256 reservedAmount = IGmxVault(VAULT).reservedAmounts(_tokenOut);
return _newPoolBalTknOut < reservedAmount;
}
function bufferAmountExceeded(uint256 _newPoolBalTknOut, address _tokenOut) internal view returns (bool) {
uint256 bufferAmount = IGmxVault(VAULT).bufferAmounts(_tokenOut);
return _newPoolBalTknOut < bufferAmount;
}
function maxDebtExceeded(uint256 _amountInUsdg, address _tokenIn) internal view returns (bool) {
uint256 maxUsdgAmount = IGmxVault(VAULT).maxUsdgAmounts(_tokenIn);
if (maxUsdgAmount == 0) return false;
uint256 newUsdgAmount = IGmxVault(VAULT).usdgAmounts(_tokenIn) + _amountInUsdg;
return newUsdgAmount > maxUsdgAmount;
}
function _getFeeBasisPoint(
address _tokenIn,
address _tokenOut,
uint256 usdgAmount
) internal view returns (uint256) {
if (USE_VAULT_UTILS)
return IGmxVault(VAULT).vaultUtils().getSwapFeeBasisPoints(_tokenIn, _tokenOut, usdgAmount);
return _calcFeeBasisPoints(_tokenIn, _tokenOut, usdgAmount);
}
function _calcFeeBasisPoints(
address _tokenIn,
address _tokenOut,
uint256 usdgAmount
) internal view returns (uint256 feeBasisPoints) {
bool isStableSwap = IGmxVault(VAULT).stableTokens(_tokenIn) && IGmxVault(VAULT).stableTokens(_tokenOut);
uint256 baseBps = isStableSwap
? IGmxVault(VAULT).stableSwapFeeBasisPoints()
: IGmxVault(VAULT).swapFeeBasisPoints();
uint256 taxBps = isStableSwap ? IGmxVault(VAULT).stableTaxBasisPoints() : IGmxVault(VAULT).taxBasisPoints();
uint256 feesBasisPoints0 = IGmxVault(VAULT).getFeeBasisPoints(_tokenIn, usdgAmount, baseBps, taxBps, true);
uint256 feesBasisPoints1 = IGmxVault(VAULT).getFeeBasisPoints(_tokenOut, usdgAmount, baseBps, taxBps, false);
// use the higher of the two fee basis points
feeBasisPoints = feesBasisPoints0 > feesBasisPoints1 ? feesBasisPoints0 : feesBasisPoints1;
}
// SWAP \\
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
IERC20(_tokenIn).safeTransfer(VAULT, _amountIn);
IGmxVault(VAULT).swap(
_tokenIn,
_tokenOut,
address(this) // No check for amount-out within swap function
);
// Confidently transfer amount-out
_returnTo(_tokenOut, _amountOut, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IKyberPool.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract KyberAdapter is SummitAdapter {
using SafeERC20 for IERC20;
uint256 public constant PRECISION = 1e18;
mapping(address => mapping(address => address)) internal TKNS_TO_POOL;
constructor(
string memory _name,
address[] memory _pools,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
addPools(_pools);
}
function addPools(address[] memory _pools) public onlyMaintainer {
// Note: Overrides existing if pool has same tkns but different APR
for (uint256 i = 0; i < _pools.length; i++) {
address tkn0 = IKyberPool(_pools[i]).token0();
address tkn1 = IKyberPool(_pools[i]).token1();
TKNS_TO_POOL[tkn0][tkn1] = _pools[i];
TKNS_TO_POOL[tkn1][tkn0] = _pools[i];
}
}
function removePools(address[] memory _pools) public onlyMaintainer {
// Note: Overrides existing if pool has same tkns but different APR
for (uint256 i = 0; i < _pools.length; i++) {
address tkn0 = IKyberPool(_pools[i]).token0();
address tkn1 = IKyberPool(_pools[i]).token1();
TKNS_TO_POOL[tkn0][tkn1] = address(0);
TKNS_TO_POOL[tkn1][tkn0] = address(0);
}
}
function getPool(address tkn0, address tkn1) public view returns (address) {
return TKNS_TO_POOL[tkn0][tkn1];
}
function _getAmountOut(
uint256 amountIn,
uint256 vReserveIn,
uint256 vReserveOut,
uint256 feeInPrecision
) internal pure returns (uint256 amountOut) {
// Based on https://github.com/dynamic-amm/smart-contracts/blob/master/contracts/libraries/DMMLibrary.sol
uint256 amountInWithFee = (amountIn * (PRECISION - feeInPrecision)) / PRECISION;
uint256 numerator = amountInWithFee * vReserveOut;
uint256 denominator = vReserveIn + amountInWithFee;
amountOut = numerator / denominator;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_tokenIn == _tokenOut || _amountIn == 0) {
return 0;
}
address pool = getPool(_tokenIn, _tokenOut);
if (pool == address(0)) {
return 0;
}
(uint112 r0, uint112 r1, uint112 vr0, uint112 vr1, uint256 feeInPrecision) = IKyberPool(pool).getTradeInfo();
(uint112 reserveIn, uint112 reserveOut) = _tokenIn < _tokenOut ? (r0, r1) : (r1, r0);
(uint112 vReserveIn, uint112 vReserveOut) = _tokenIn < _tokenOut ? (vr0, vr1) : (vr1, vr0);
if (reserveIn > 0 && reserveOut > 0) {
uint256 _amountOut = _getAmountOut(_amountIn, vReserveIn, vReserveOut, feeInPrecision);
if (reserveOut > amountOut) amountOut = _amountOut;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
address pair = getPool(_tokenIn, _tokenOut);
(uint256 amount0Out, uint256 amount1Out) = (_tokenIn < _tokenOut)
? (uint256(0), _amountOut)
: (_amountOut, uint256(0));
IERC20(_tokenIn).safeTransfer(pair, _amountIn);
IKyberPool(pair).swap(amount0Out, amount1Out, to, new bytes(0));
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "./UniswapV3likeAdapter.sol";
interface IKyberPool {
function token0() external view returns (address);
function token1() external view returns (address);
function swap(
address recipient,
int256 swapQty,
bool isToken0,
uint160 limitSqrtP,
bytes calldata data
) external returns (int256 qty0, int256 qty1);
}
contract KyberElasticAdapter is UniswapV3likeAdapter {
using SafeERC20 for IERC20;
mapping(address => mapping(address => address)) public tknsToPoolWL;
constructor(
string memory _name,
uint256 _swapGasEstimate,
uint256 _quoterGasLimit,
address _quoter,
address[] memory _whitelistedPools
) UniswapV3likeAdapter(_name, _swapGasEstimate, _quoter, _quoterGasLimit) {
addPoolsToWL(_whitelistedPools);
}
function addPoolsToWL(address[] memory pools) public onlyMaintainer {
for (uint256 i; i < pools.length; ++i) addPoolToWL(pools[i]);
}
function rmPoolsFromWL(address[] memory pools) external onlyMaintainer {
for (uint256 i; i < pools.length; ++i) rmPoolFromWL(pools[i]);
}
function addPoolToWL(address pool) internal {
address t0 = IKyberPool(pool).token0();
address t1 = IKyberPool(pool).token1();
tknsToPoolWL[t0][t1] = pool;
tknsToPoolWL[t1][t0] = pool;
}
function rmPoolFromWL(address pool) internal {
address t0 = IKyberPool(pool).token0();
address t1 = IKyberPool(pool).token1();
tknsToPoolWL[t0][t1] = address(0);
tknsToPoolWL[t1][t0] = address(0);
}
function _underlyingSwap(
QParams memory params,
bytes memory callbackData
) internal override returns (uint256) {
address pool = getBestPool(params.tokenIn, params.tokenOut);
(bool zeroForOne, uint160 sqrtPriceLimitX96) =
getZeroOneAndSqrtPriceLimitX96(params.tokenIn, params.tokenOut);
(int256 amount0, int256 amount1) = IKyberPool(pool).swap(
address(this),
int256(params.amountIn),
zeroForOne,
sqrtPriceLimitX96,
callbackData
);
return zeroForOne ? uint256(-amount1) : uint256(-amount0);
}
function getBestPool(
address token0,
address token1
) internal view override returns (address) {
return tknsToPoolWL[token0][token1];
}
function swapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata
) external {
if (amount0Delta > 0) {
IERC20(IKyberPool(msg.sender).token0()).transfer(msg.sender, uint256(amount0Delta));
} else {
IERC20(IKyberPool(msg.sender).token1()).transfer(msg.sender, uint256(amount1Delta));
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../SummitAdapter.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../interface/ILBFactory.sol";
import "../interface/ILB2Pair.sol";
struct LBQuote {
uint256 amountOut;
address pair;
bool swapForY;
}
contract LB2Adapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable FACTORY;
bool public allowIgnoredPairs = true;
bool public allowExternalPairs = true;
uint256 public quoteGasLimit = 600_000;
constructor(
string memory _name,
uint256 _swapGasEstimate,
uint256 _quoteGasLimit,
address _factory
) SummitAdapter(_name, _swapGasEstimate) {
setQuoteGasLimit(_quoteGasLimit);
FACTORY = _factory;
}
function setAllowIgnoredPairs(bool _allowIgnoredPairs) external onlyMaintainer {
allowIgnoredPairs = _allowIgnoredPairs;
}
function setAllowExternalPairs(bool _allowExternalPairs) external onlyMaintainer {
allowExternalPairs = _allowExternalPairs;
}
function setQuoteGasLimit(uint256 _quoteGasLimit) public onlyMaintainer {
quoteGasLimit = _quoteGasLimit;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
(amountOut, , ) = _getBestQuote(_amountIn, _tokenIn, _tokenOut);
}
function _swap(
uint256 _amountIn,
uint256 _minAmountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
(uint256 amountOut, address pair, bool swapForY) = _getBestQuote(_amountIn, _tokenIn, _tokenOut);
require(amountOut >= _minAmountOut, "LBAdapter: insufficient amountOut received");
IERC20(_tokenIn).transfer(pair, _amountIn);
ILBPair(pair).swap(swapForY, to);
}
function _getBestQuote(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
)
internal
view
returns (
uint256 amountOut,
address pair,
bool swapForY
)
{
ILBFactory.LBPairInformation[] memory LBPairsAvailable = ILBFactory(FACTORY).getAllLBPairs(_tokenIn, _tokenOut);
if (LBPairsAvailable.length > 0 && _amountIn > 0) {
for (uint256 i; i < LBPairsAvailable.length; ++i) {
if (!LBPairsAvailable[i].ignoredForRouting && !allowIgnoredPairs) {
continue;
}
if (!LBPairsAvailable[i].createdByOwner && !allowExternalPairs) {
continue;
}
swapForY = ILBPair(LBPairsAvailable[i].LBPair).getTokenY() == _tokenOut;
uint256 swapAmountOut = getQuote(LBPairsAvailable[i].LBPair, _amountIn, swapForY);
if (swapAmountOut > amountOut) {
amountOut = swapAmountOut;
pair = LBPairsAvailable[i].LBPair;
}
}
}
}
function getQuote(
address pair,
uint256 amountIn,
bool swapForY
) internal view returns (uint256 out) {
try ILBPair(pair).getSwapOut{gas: quoteGasLimit}(
uint128(amountIn),
swapForY
) returns (uint128 amountInLeft, uint128 amountOut, uint128) {
if (amountInLeft == 0) {
out = amountOut;
}
} catch {}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../SummitAdapter.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../interface/ILBRouter.sol";
import "../interface/ILBFactory.sol";
import "../interface/ILBPair.sol";
struct LBQuote {
uint256 amountOut;
address pair;
bool swapForY;
}
contract LBAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable FACTORY;
address public immutable ROUTER;
bool public allowIgnoredPairs = true;
bool public allowExternalPairs = true;
uint256 public quoteGasLimit = 600_000;
constructor(
string memory _name,
uint256 _swapGasEstimate,
address _router
) SummitAdapter(_name, _swapGasEstimate) {
FACTORY = ILBRouter(_router).factory();
ROUTER = _router;
}
function setAllowIgnoredPairs(bool _allowIgnoredPairs) external onlyMaintainer {
allowIgnoredPairs = _allowIgnoredPairs;
}
function setAllowExternalPairs(bool _allowExternalPairs) external onlyMaintainer {
allowExternalPairs = _allowExternalPairs;
}
function setQuoteGasLimit(uint256 _quoteGasLimit) external onlyMaintainer {
quoteGasLimit = _quoteGasLimit;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
(amountOut, , ) = _getBestQuote(_amountIn, _tokenIn, _tokenOut);
}
function _swap(
uint256 _amountIn,
uint256 _minAmountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
(uint256 amountOut, address pair, bool swapForY) = _getBestQuote(_amountIn, _tokenIn, _tokenOut);
require(amountOut >= _minAmountOut, "LBAdapter: insufficient amountOut received");
IERC20(_tokenIn).transfer(pair, _amountIn);
ILBPair(pair).swap(swapForY, to);
}
function _getBestQuote(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
)
internal
view
returns (
uint256 amountOut,
address pair,
bool swapForY
)
{
ILBFactory.LBPairInformation[] memory LBPairsAvailable = ILBFactory(FACTORY).getAllLBPairs(_tokenIn, _tokenOut);
if (LBPairsAvailable.length > 0 && _amountIn > 0) {
for (uint256 i; i < LBPairsAvailable.length; ++i) {
if (!LBPairsAvailable[i].ignoredForRouting && !allowIgnoredPairs) {
continue;
}
if (!LBPairsAvailable[i].createdByOwner && !allowExternalPairs) {
continue;
}
swapForY = ILBPair(LBPairsAvailable[i].LBPair).tokenY() == _tokenOut;
uint256 swapAmountOut = getQuote(LBPairsAvailable[i].LBPair, _amountIn, swapForY);
if (swapAmountOut > amountOut) {
amountOut = swapAmountOut;
pair = LBPairsAvailable[i].LBPair;
}
}
}
}
function getQuote(
address pair,
uint256 amountIn,
bool swapForY
) internal view returns (uint256 amountOut) {
bytes memory calldata_ = abi.encodeWithSignature("getSwapOut(address,uint256,bool)", pair, amountIn, swapForY);
(bool success, bytes memory data) = ROUTER.staticcall{ gas: quoteGasLimit }(calldata_);
if (success)
assembly {
amountOut := mload(add(data, 0x20))
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ImSUMMIT.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract MiniSummitAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address public constant SUMMIT = 0x59414b3089ce2AF0010e7523Dea7E2b35d776ec7;
address public constant mSUMMIT = 0xdDAaAD7366B455AfF8E7c82940C43CEB5829B604;
constructor(uint256 _swapGasEstimate) SummitAdapter("MiniSummitAdapter", _swapGasEstimate) {
setAllowances();
}
function setAllowances() internal {
IERC20(mSUMMIT).safeApprove(mSUMMIT, UINT_MAX);
IERC20(SUMMIT).safeApprove(mSUMMIT, UINT_MAX);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal pure override returns (uint256 amountOut) {
if ((_tokenIn == mSUMMIT && _tokenOut == SUMMIT) || (_tokenIn == SUMMIT && _tokenOut == mSUMMIT)) {
amountOut = _amountIn;
}
}
function _swap(
uint256 _amountIn,
uint256,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
if (_tokenIn == mSUMMIT && _tokenOut == SUMMIT) {
ImSUMMIT(mSUMMIT).unmoon(_amountIn, _to);
} else if (_tokenIn == SUMMIT && _tokenOut == mSUMMIT) {
ImSUMMIT(mSUMMIT).moon(_amountIn, _to);
} else {
revert("Unsupported token");
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// ,=.
// ,=""""==.__.=" o".___
// ,=.==" ___/
// ,==.," , , \,===""
// < ,==) \"'"=._.==) \
// `=='' `" `"
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IPlatypus.sol";
import "../interface/IERC20.sol";
import "../interface/IWETH.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract PlatypusAdapter is SummitAdapter {
using SafeERC20 for IERC20;
event PartialPoolSupport(address pool, address[] tkns);
event AddPoolSupport(address pool);
event RmPoolSupport(address pool);
mapping(address => mapping(address => address)) private tknToTknToPool;
constructor(
string memory _name,
uint256 _swapGasEstimate,
address[] memory _initPools
) SummitAdapter(_name, _swapGasEstimate) {
addPools(_initPools);
}
function getPoolForTkns(address tknIn, address tknOut) public view returns (address) {
return tknToTknToPool[tknIn][tknOut];
}
function _approveIfNeeded(address tkn, address spender) internal {
uint256 allowance = IERC20(tkn).allowance(address(this), spender);
if (allowance < UINT_MAX) {
IERC20(tkn).approve(spender, UINT_MAX);
}
}
// @dev Returns false if repeated tkns
function _poolSupportsTkns(address pool, address[] memory tkns) internal view returns (bool) {
address[] memory supportedTkns = IPlatypus(pool).getTokenAddresses();
uint256 supportedCount;
for (uint256 i = 0; i < supportedTkns.length; i++) {
for (uint256 j = 0; j < tkns.length; j++) {
if (supportedTkns[i] == tkns[j]) {
supportedCount++;
break;
}
}
}
return supportedCount == tkns.length;
}
function _setPoolForTkns(address[] memory tkns, address pool) internal {
for (uint256 i = 0; i < tkns.length; i++) {
for (uint256 j = 0; j < tkns.length; j++) {
if (i != j) {
tknToTknToPool[tkns[i]][tkns[j]] = pool;
if (pool != address(0)) {
_approveIfNeeded(tkns[i], pool);
}
}
}
}
}
function addPools(address[] memory pools) public onlyMaintainer {
for (uint256 i = 0; i < pools.length; i++) {
address pool = pools[i];
address[] memory supportedTkns = IPlatypus(pool).getTokenAddresses();
_setPoolForTkns(supportedTkns, pool);
emit AddPoolSupport(pool);
}
}
function setPoolForTkns(address pool, address[] memory tkns) external onlyMaintainer {
require(tkns.length > 1, "At least two tkns");
require(pool != address(0), "Only non-zero pool");
require(_poolSupportsTkns(pool, tkns), "Pool does not support tkns");
// Assume above checks there is no repeats
_setPoolForTkns(tkns, pool);
emit PartialPoolSupport(pool, tkns);
}
function rmPools(address[] calldata pools) external onlyMaintainer {
for (uint256 i = 0; i < pools.length; i++) {
address pool = pools[i];
address[] memory supportedTkns = IPlatypus(pool).getTokenAddresses();
_setPoolForTkns(supportedTkns, address(0));
emit RmPoolSupport(pool);
}
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
address pool = getPoolForTkns(_tokenIn, _tokenOut);
if (pool == address(0) || _amountIn == 0 || IPlatypus(pool).paused()) {
return 0;
}
try IPlatypus(pool).quotePotentialSwap(_tokenIn, _tokenOut, _amountIn) returns (uint256 amountOut) {
return amountOut;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
address pool = getPoolForTkns(_tokenIn, _tokenOut);
IPlatypus(pool).swap(_tokenIn, _tokenOut, _amountIn, _amountOut, _to, block.timestamp);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "./UniswapV3likeAdapter.sol";
interface IUniV3Factory {
function feeAmountTickSpacing(uint24) external view returns (int24);
function getPool(
address,
address,
uint24
) external view returns (address);
}
contract RamsesV2Adapter is UniswapV3likeAdapter {
using SafeERC20 for IERC20;
address immutable FACTORY;
mapping(uint24 => bool) public isFeeAmountEnabled;
uint24[] public feeAmounts;
constructor(
string memory _name,
uint256 _swapGasEstimate,
uint256 _quoterGasLimit,
address _quoter,
address _factory,
uint24[] memory _defaultFees
) UniswapV3likeAdapter(_name, _swapGasEstimate, _quoter, _quoterGasLimit) {
FACTORY = _factory;
for (uint i = 0; i < _defaultFees.length; i++) {
addFeeAmount(_defaultFees[i]);
}
}
function enableFeeAmounts(uint24[] calldata _amounts) external onlyMaintainer {
for (uint256 i; i < _amounts.length; ++i) enableFeeAmount(_amounts[i]);
}
function enableFeeAmount(uint24 _fee) internal {
require(!isFeeAmountEnabled[_fee], "Fee already enabled");
if (IUniV3Factory(FACTORY).feeAmountTickSpacing(_fee) == 0)
revert("Factory doesn't support fee");
addFeeAmount(_fee);
}
function addFeeAmount(uint24 _fee) internal {
isFeeAmountEnabled[_fee] = true;
feeAmounts.push(_fee);
}
function getBestPool(
address token0,
address token1
) internal view override returns (address mostLiquid) {
uint128 deepestLiquidity;
for (uint256 i; i < feeAmounts.length; ++i) {
address pool = IUniV3Factory(FACTORY).getPool(token0, token1, feeAmounts[i]);
if (pool == address(0))
continue;
uint128 liquidity = IUniV3Pool(pool).liquidity();
if (liquidity > deepestLiquidity) {
deepestLiquidity = liquidity;
mostLiquid = pool;
}
}
}
function ramsesV2SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata
) external {
if (amount0Delta > 0) {
IERC20(IUniV3Pool(msg.sender).token0()).transfer(msg.sender, uint256(amount0Delta));
} else {
IERC20(IUniV3Pool(msg.sender).token1()).transfer(msg.sender, uint256(amount1Delta));
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import { SummitAdapter, IERC20, SafeERC20 } from "../SummitAdapter.sol";
import { IGenericFactory } from "../interface/IGenericFactory.sol";
import { IQuoter } from "../interface/IReservoirQuoter.sol";
import { IReservoirPair } from "../interface/IReservoirPair.sol";
contract ReservoirAdapter is SummitAdapter {
using SafeERC20 for IERC20;
uint256 internal constant FEE_ACCURACY = 1_000_000;
IGenericFactory public immutable factory;
IQuoter public immutable quoter;
constructor(
string memory _name,
address _factory,
address _quoter,
uint256 _swapGasEstimate // we use the worse off i.e. the stable pair gas estimate
) SummitAdapter(_name, _swapGasEstimate) {
factory = IGenericFactory(_factory);
quoter = IQuoter(_quoter);
}
function _queryWithCurveId(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256 amountOut, uint256 curveId) {
if (_tokenIn == _tokenOut || _amountIn == 0) {
return (0, 0);
}
address[] memory path = new address[](2);
path[0] = _tokenIn;
path[1] = _tokenOut;
uint256[] memory curveIds = new uint256[](1);
curveIds[0] = 0;
uint256 constantProductAmtOut;
// try get quote for constant product pair
try quoter.getAmountsOut(_amountIn, path, curveIds) returns (uint256[] memory amtsOut) {
constantProductAmtOut = amtsOut[1];
} catch {}
curveIds[0] = 1;
uint256 stableAmtOut;
// try get quote for stable pair
try quoter.getAmountsOut(_amountIn, path, curveIds) returns (uint256[] memory amtsOut) {
stableAmtOut = amtsOut[1];
} catch {}
return stableAmtOut > constantProductAmtOut ? (stableAmtOut, 1) : (constantProductAmtOut, 0);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
(amountOut, ) = _queryWithCurveId(_amountIn, _tokenIn, _tokenOut);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
(uint256 amountOut, uint256 curveId) = _queryWithCurveId(_amountIn, _tokenIn, _tokenOut);
require(amountOut >= _amountOut, "ResAdap: Insufficient amount out");
address pair = factory.getPair(_tokenIn, _tokenOut, curveId);
address token0 = IReservoirPair(pair).token0();
IERC20(_tokenIn).safeTransfer(pair, _amountIn);
IReservoirPair(pair).swap(
_tokenIn == token0 ? int256(_amountIn) : -int256(_amountIn),
true,
to,
new bytes(0)
);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ISaddle.sol";
import "../interface/IERC20.sol";
import "../interface/IWETH.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract SaddleAdapter is SummitAdapter {
using SafeERC20 for IERC20;
mapping(address => bool) public isPoolToken;
mapping(address => uint8) public tokenIndex;
address public pool;
constructor(
string memory _name,
address _pool,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
pool = _pool;
_setPoolTokens();
}
function _setPoolTokens() internal {
for (uint8 i = 0; true; i++) {
try ISaddle(pool).getToken(i) returns (address token) {
approveToPool(token, UINT_MAX);
isPoolToken[token] = true;
tokenIndex[token] = i;
} catch {
break;
}
}
}
function approveToPool(address _tokenIn, uint256 _amount) internal {
uint256 allowance = IERC20(_tokenIn).allowance(address(this), pool);
if (allowance < _amount) {
IERC20(_tokenIn).safeApprove(pool, UINT_MAX);
}
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (
!isPoolToken[_tokenIn] ||
!isPoolToken[_tokenOut] ||
_tokenIn == _tokenOut ||
_amountIn == 0 ||
ISaddle(pool).paused()
) {
return 0;
}
try ISaddle(pool).calculateSwap(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 amountOut
) {
return amountOut;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
// Note that unsupported token will return index 0 which is valid
ISaddle(pool).swap(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn, _amountOut, block.timestamp);
// Confidently transfer amount-out
_returnTo(_tokenOut, _amountOut, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/ISaddleMeta.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract SaddleMetaAdapter is SummitAdapter {
using SafeERC20 for IERC20;
uint256 public constant feeDenominator = 1e10;
mapping(address => bool) public isPoolToken;
mapping(address => uint8) public tokenIndex;
uint256 public poolFeeCompliment;
address public metaPool;
address public metaTkn;
address public pool;
constructor(
string memory _name,
address _pool,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
pool = _pool;
metaPool = ISaddleMeta(pool).metaSwapStorage(); // Pool that holds USDCe, USDTe, DAIe
_setPoolTokens();
}
// Mapping indicator which tokens are included in the pool
function _setPoolTokens() internal {
metaTkn = ISaddleMeta(pool).getToken(0);
approveToPool(metaTkn, UINT_MAX);
tokenIndex[metaTkn] = 0;
for (uint8 i = 0; true; i++) {
try ISaddleMeta(metaPool).getToken(i) returns (address token) {
approveToPool(token, UINT_MAX);
isPoolToken[token] = true;
tokenIndex[token] = i + 1;
} catch {
break;
}
}
}
function approveToPool(address _tokenIn, uint256 _amount) internal {
uint256 allowance = IERC20(_tokenIn).allowance(address(this), pool);
if (allowance < _amount) {
IERC20(_tokenIn).safeApprove(pool, UINT_MAX);
}
}
function _isPaused() internal view returns (bool) {
return ISaddleMeta(pool).paused() || ISaddleMeta(metaPool).paused();
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (validInput(_amountIn, _tokenIn, _tokenOut) && !_isPaused())
amountOut = _getAmountOutSafe(_amountIn, _tokenIn, _tokenOut);
}
function validInput(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (bool) {
return validPath(_tokenIn, _tokenOut) && _amountIn != 0;
}
function validPath(address tokenIn, address tokenOut) internal view returns (bool) {
return (tokenIn == metaTkn && isPoolToken[tokenOut]) || (tokenOut == metaTkn && isPoolToken[tokenIn]);
}
function _getAmountOutSafe(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256 amountOut) {
try ISaddleMeta(pool).calculateSwapUnderlying(tokenIndex[_tokenIn], tokenIndex[_tokenOut], _amountIn) returns (
uint256 _amountOut
) {
amountOut = _applyError(_amountOut);
} catch {}
}
function _applyError(uint256 _amount) internal pure returns (uint256) {
return (_amount * 9998) / 10000;
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
ISaddleMeta(pool).swapUnderlying(
tokenIndex[_tokenIn],
tokenIndex[_tokenOut],
_amountIn,
_amountOut,
block.timestamp
);
uint256 balThis = IERC20(_tokenOut).balanceOf(address(this));
_returnTo(_tokenOut, balThis, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IUniswapFactory.sol";
import "../interface/IUniswapPair.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract UniswapV2Adapter is SummitAdapter {
using SafeERC20 for IERC20;
uint256 internal constant FEE_DENOMINATOR = 1e3;
uint256 public immutable feeCompliment;
address public immutable factory;
constructor(
string memory _name,
address _factory,
uint256 _fee,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
feeCompliment = FEE_DENOMINATOR - _fee;
factory = _factory;
}
function _getAmountOut(
uint256 _amountIn,
uint256 _reserveIn,
uint256 _reserveOut
) internal view returns (uint256 amountOut) {
// Based on https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/UniswapV2Router02.sol
uint256 amountInWithFee = _amountIn * feeCompliment;
uint256 numerator = amountInWithFee * _reserveOut;
uint256 denominator = _reserveIn * FEE_DENOMINATOR + amountInWithFee;
amountOut = numerator / denominator;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_tokenIn == _tokenOut || _amountIn == 0) {
return 0;
}
address pair = IUniswapFactory(factory).getPair(_tokenIn, _tokenOut);
if (pair == address(0)) {
return 0;
}
(uint256 r0, uint256 r1, ) = IUniswapPair(pair).getReserves();
(uint256 reserveIn, uint256 reserveOut) = _tokenIn < _tokenOut ? (r0, r1) : (r1, r0);
if (reserveIn > 0 && reserveOut > 0) {
amountOut = _getAmountOut(_amountIn, reserveIn, reserveOut);
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
address pair = IUniswapFactory(factory).getPair(_tokenIn, _tokenOut);
(uint256 amount0Out, uint256 amount1Out) = (_tokenIn < _tokenOut)
? (uint256(0), _amountOut)
: (_amountOut, uint256(0));
IERC20(_tokenIn).safeTransfer(pair, _amountIn);
IUniswapPair(pair).swap(amount0Out, amount1Out, to, new bytes(0));
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "./UniswapV3AdapterBase.sol";
contract UniswapV3Adapter is UniswapV3AdapterBase {
constructor(
string memory _name,
uint256 _swapGasEstimate,
uint256 _quoterGasLimit,
address _quoter,
address _factory,
uint24[] memory _defaultFees
) UniswapV3AdapterBase(_name, _swapGasEstimate, _quoterGasLimit, _quoter, _factory, _defaultFees) {
}
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata
) external {
if (amount0Delta > 0) {
IERC20(IUniV3Pool(msg.sender).token0()).transfer(msg.sender, uint256(amount0Delta));
} else {
IERC20(IUniV3Pool(msg.sender).token1()).transfer(msg.sender, uint256(amount1Delta));
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "./UniswapV3likeAdapter.sol";
interface IUniV3Factory {
function feeAmountTickSpacing(uint24) external view returns (int24);
function getPool(
address,
address,
uint24
) external view returns (address);
}
contract UniswapV3AdapterBase is UniswapV3likeAdapter {
using SafeERC20 for IERC20;
address immutable FACTORY;
mapping(uint24 => bool) public isFeeAmountEnabled;
uint24[] public feeAmounts;
constructor(
string memory _name,
uint256 _swapGasEstimate,
uint256 _quoterGasLimit,
address _quoter,
address _factory,
uint24[] memory _defaultFees
) UniswapV3likeAdapter(_name, _swapGasEstimate, _quoter, _quoterGasLimit) {
FACTORY = _factory;
for (uint i = 0; i < _defaultFees.length; i++) {
addFeeAmount(_defaultFees[i]);
}
}
function enableFeeAmounts(uint24[] calldata _amounts) external onlyMaintainer {
for (uint256 i; i < _amounts.length; ++i) enableFeeAmount(_amounts[i]);
}
function enableFeeAmount(uint24 _fee) internal {
require(!isFeeAmountEnabled[_fee], "Fee already enabled");
if (IUniV3Factory(FACTORY).feeAmountTickSpacing(_fee) == 0)
revert("Factory doesn't support fee");
addFeeAmount(_fee);
}
function addFeeAmount(uint24 _fee) internal {
isFeeAmountEnabled[_fee] = true;
feeAmounts.push(_fee);
}
function getBestPool(
address token0,
address token1
) internal view override returns (address mostLiquid) {
uint128 deepestLiquidity;
for (uint256 i; i < feeAmounts.length; ++i) {
address pool = IUniV3Factory(FACTORY).getPool(token0, token1, feeAmounts[i]);
if (pool == address(0))
continue;
uint128 liquidity = IUniV3Pool(pool).liquidity();
if (liquidity > deepestLiquidity) {
deepestLiquidity = liquidity;
mostLiquid = pool;
}
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
struct QParams {
address tokenIn;
address tokenOut;
int256 amountIn;
uint24 fee;
}
interface IUniV3Pool {
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
function token0() external view returns (address);
function token1() external view returns (address);
function liquidity() external view returns (uint128);
}
interface IUniV3Quoter {
function quoteExactInputSingle(
QParams memory params
) external view returns (uint256);
function quote(
address,
bool,
int256,
uint160
) external view returns (int256, int256);
}
abstract contract UniswapV3likeAdapter is SummitAdapter {
using SafeERC20 for IERC20;
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
uint256 public quoterGasLimit;
address public quoter;
constructor(
string memory _name,
uint256 _swapGasEstimate,
address _quoter,
uint256 _quoterGasLimit
) SummitAdapter(_name, _swapGasEstimate) {
setQuoterGasLimit(_quoterGasLimit);
setQuoter(_quoter);
}
function setQuoter(address newQuoter) public onlyMaintainer {
quoter = newQuoter;
}
function setQuoterGasLimit(uint256 newLimit) public onlyMaintainer {
require(newLimit != 0, "queryGasLimit can't be zero");
quoterGasLimit = newLimit;
}
function getQuoteForPool(
address pool,
int256 amountIn,
address tokenIn,
address tokenOut
) external view returns (uint256) {
QParams memory params;
params.amountIn = amountIn;
params.tokenIn = tokenIn;
params.tokenOut = tokenOut;
return getQuoteForPool(pool, params);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 quote) {
QParams memory params = getQParams(_amountIn, _tokenIn, _tokenOut);
quote = getQuoteForBestPool(params);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
QParams memory params = getQParams(_amountIn, _tokenIn, _tokenOut);
uint256 amountOut = _underlyingSwap(params, new bytes(0));
require(amountOut >= _amountOut, "Insufficient amountOut");
_returnTo(_tokenOut, amountOut, _to);
}
function getQParams(
uint256 amountIn,
address tokenIn,
address tokenOut
) internal pure returns (QParams memory params) {
params = QParams({
amountIn: int256(amountIn),
tokenIn: tokenIn,
tokenOut: tokenOut,
fee: 0
});
}
function _underlyingSwap(
QParams memory params,
bytes memory callbackData
) internal virtual returns (uint256) {
address pool = getBestPool(params.tokenIn, params.tokenOut);
(bool zeroForOne, uint160 priceLimit) = getZeroOneAndSqrtPriceLimitX96(
params.tokenIn,
params.tokenOut
);
(int256 amount0, int256 amount1) = IUniV3Pool(pool).swap(
address(this),
zeroForOne,
int256(params.amountIn),
priceLimit,
callbackData
);
return zeroForOne ? uint256(-amount1) : uint256(-amount0);
}
function getQuoteForBestPool(
QParams memory params
) internal view returns (uint256 quote) {
address bestPool = getBestPool(params.tokenIn, params.tokenOut);
if (bestPool != address(0)) quote = getQuoteForPool(bestPool, params);
}
function getBestPool(
address token0,
address token1
) internal view virtual returns (address mostLiquid);
function getQuoteForPool(
address pool,
QParams memory params
) internal view returns (uint256) {
(bool zeroForOne, uint160 priceLimit) = getZeroOneAndSqrtPriceLimitX96(
params.tokenIn,
params.tokenOut
);
(int256 amount0, int256 amount1) = getQuoteSafe(
pool,
zeroForOne,
params.amountIn,
priceLimit
);
return zeroForOne ? uint256(-amount1) : uint256(-amount0);
}
function getQuoteSafe(
address pool,
bool zeroForOne,
int256 amountIn,
uint160 priceLimit
) internal view returns (int256 amount0, int256 amount1) {
bytes memory calldata_ = abi.encodeWithSignature(
"quote(address,bool,int256,uint160)",
pool,
zeroForOne,
amountIn,
priceLimit
);
(bool success, bytes memory data) = staticCallQuoterRaw(calldata_);
if (success)
(amount0, amount1) = abi.decode(data, (int256, int256));
}
function staticCallQuoterRaw(
bytes memory calldata_
) internal view returns (bool success, bytes memory data) {
(success, data) = quoter.staticcall{gas: quoterGasLimit}(calldata_);
}
function getZeroOneAndSqrtPriceLimitX96(address tokenIn, address tokenOut)
internal
pure
returns (bool zeroForOne, uint160 sqrtPriceLimitX96)
{
zeroForOne = tokenIn < tokenOut;
sqrtPriceLimitX96 = zeroForOne ? MIN_SQRT_RATIO+1 : MAX_SQRT_RATIO-1;
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
interface IPairFactory {
function isPair(address) external view returns (bool);
function pairCodeHash() external view returns (bytes32);
}
interface IPair {
function getAmountOut(uint256, address) external view returns (uint256);
function swap(
uint256,
uint256,
address,
bytes calldata
) external;
}
contract VelodromeAdapter is SummitAdapter {
using SafeERC20 for IERC20;
bytes32 immutable PAIR_CODE_HASH;
address immutable FACTORY;
constructor(
string memory _name,
address _factory,
uint256 _swapGasEstimate
) SummitAdapter(_name, _swapGasEstimate) {
FACTORY = _factory;
PAIR_CODE_HASH = getPairCodeHash(_factory);
}
function getPairCodeHash(address _factory) internal view returns (bytes32) {
return IPairFactory(_factory).pairCodeHash();
}
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
}
// calculates the CREATE2 address for a pair without making any external calls
function pairFor(
address tokenA,
address tokenB,
bool stable
) internal view returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
FACTORY,
keccak256(abi.encodePacked(token0, token1, stable)),
PAIR_CODE_HASH
)
)
)
)
);
}
function _getAmoutOutSafe(address pair, uint amountIn, address tokenIn) internal view returns (uint) {
try IPair(pair).getAmountOut(amountIn, tokenIn) returns (uint amountOut) {
return amountOut;
} catch {
return 0;
}
}
function getQuoteAndPair(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view returns (uint256 amountOut, address pair) {
address pairStable = pairFor(_tokenIn, _tokenOut, true);
uint256 amountStable;
uint256 amountVolatile;
if (IPairFactory(FACTORY).isPair(pairStable)) {
amountStable = _getAmoutOutSafe(pairStable, _amountIn, _tokenIn);
}
address pairVolatile = pairFor(_tokenIn, _tokenOut, false);
if (IPairFactory(FACTORY).isPair(pairVolatile)) {
amountVolatile = _getAmoutOutSafe(pairVolatile, _amountIn, _tokenIn);
}
(amountOut, pair) = amountStable > amountVolatile ? (amountStable, pairStable) : (amountVolatile, pairVolatile);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_tokenIn != _tokenOut && _amountIn != 0) (amountOut, ) = getQuoteAndPair(_amountIn, _tokenIn, _tokenOut);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
(uint256 amountOut, address pair) = getQuoteAndPair(_amountIn, _tokenIn, _tokenOut);
require(amountOut >= _amountOut, "Insufficent amount out");
(uint256 amount0Out, uint256 amount1Out) = (_tokenIn < _tokenOut)
? (uint256(0), amountOut)
: (amountOut, uint256(0));
IERC20(_tokenIn).safeTransfer(pair, _amountIn);
IPair(pair).swap(amount0Out, amount1Out, to, new bytes(0));
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../SummitAdapter.sol";
contract WAvaxAdapter is SummitAdapter {
address internal constant WAVAX = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7;
constructor(uint256 _swapGasEstimate) SummitAdapter("WAvaxAdapter", _swapGasEstimate) {
setSwapGasEstimate(_swapGasEstimate);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal pure override returns (uint256 amountOut) {
if (_tokenIn == WAVAX && _tokenOut == WAVAX) {
amountOut = _amountIn;
}
}
function _swap(
uint256,
uint256 _amountOut,
address,
address _tokenOut,
address _to
) internal override {
_returnTo(_tokenOut, _amountOut, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../SummitAdapter.sol";
contract WNativeAdapter is SummitAdapter {
address internal immutable WNATIVE;
constructor(
address _wNative,
uint256 _swapGasEstimate
) SummitAdapter("WAvaxAdapter", _swapGasEstimate) {
WNATIVE = _wNative;
setSwapGasEstimate(_swapGasEstimate);
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_tokenIn == WNATIVE && _tokenOut == WNATIVE)
amountOut = _amountIn;
}
function _swap(
uint256 _amountIn,
uint256,
address,
address _tokenOut,
address _to
) internal override {
_returnTo(_tokenOut, _amountIn, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// ,=.
// ,=""""==.__.=" o".___
// ,=.==" ___/
// ,==.," , , \,===""
// < ,==) \"'"=._.==) \
// `=='' `" `"
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IWombat.sol";
import "../interface/IERC20.sol";
import "../interface/IWETH.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract WombatAdapter is SummitAdapter {
using SafeERC20 for IERC20;
event PartialPoolSupport(address pool, address[] tkns);
event AddPoolSupport(address pool);
event RmPoolSupport(address pool);
mapping(address => mapping(address => address)) private tknToTknToPool;
constructor(
string memory _name,
uint256 _swapGasEstimate,
address[] memory _initPools
) SummitAdapter(_name, _swapGasEstimate) {
addPools(_initPools);
}
function getPoolForTkns(address tknIn, address tknOut) public view returns (address) {
return tknToTknToPool[tknIn][tknOut];
}
function _approveIfNeeded(address tkn, address spender) internal {
uint256 allowance = IERC20(tkn).allowance(address(this), spender);
if (allowance < UINT_MAX) {
IERC20(tkn).approve(spender, UINT_MAX);
}
}
// @dev Returns false if repeated tkns
function _poolSupportsTkns(address pool, address[] memory tkns) internal view returns (bool) {
address[] memory supportedTkns = IWombat(pool).getTokens();
uint256 supportedCount;
for (uint256 i = 0; i < supportedTkns.length; i++) {
for (uint256 j = 0; j < tkns.length; j++) {
if (supportedTkns[i] == tkns[j]) {
supportedCount++;
break;
}
}
}
return supportedCount == tkns.length;
}
function _setPoolForTkns(address[] memory tkns, address pool) internal {
for (uint256 i = 0; i < tkns.length; i++) {
for (uint256 j = 0; j < tkns.length; j++) {
if (i != j) {
tknToTknToPool[tkns[i]][tkns[j]] = pool;
if (pool != address(0)) {
_approveIfNeeded(tkns[i], pool);
}
}
}
}
}
function addPools(address[] memory pools) public onlyMaintainer {
for (uint256 i = 0; i < pools.length; i++) {
address pool = pools[i];
address[] memory supportedTkns = IWombat(pool).getTokens();
_setPoolForTkns(supportedTkns, pool);
emit AddPoolSupport(pool);
}
}
function setPoolForTkns(address pool, address[] memory tkns) external onlyMaintainer {
require(tkns.length > 1, "At least two tkns");
require(pool != address(0), "Only non-zero pool");
require(_poolSupportsTkns(pool, tkns), "Pool does not support tkns");
// Assume above checks there is no repeats
_setPoolForTkns(tkns, pool);
emit PartialPoolSupport(pool, tkns);
}
function rmPools(address[] calldata pools) external onlyMaintainer {
for (uint256 i = 0; i < pools.length; i++) {
address pool = pools[i];
address[] memory supportedTkns = IWombat(pool).getTokens();
_setPoolForTkns(supportedTkns, address(0));
emit RmPoolSupport(pool);
}
}
function _query(uint256 _amountIn, address _tokenIn, address _tokenOut) internal view override returns (uint256) {
address pool = getPoolForTkns(_tokenIn, _tokenOut);
if (pool == address(0) || _amountIn == 0 || IWombat(pool).paused()) {
return 0;
}
try IWombat(pool).quotePotentialSwap(_tokenIn, _tokenOut, int256(_amountIn)) returns (uint256 amountOut) {
return amountOut;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
address pool = getPoolForTkns(_tokenIn, _tokenOut);
IWombat(pool).swap(_tokenIn, _tokenOut, _amountIn, _amountOut, _to, block.timestamp);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IWooPP.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract WoofiAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable quoteToken;
address public immutable pool;
address public rebateCollector;
constructor(
string memory _name,
uint256 _swapGasEstimate,
address _pool
) SummitAdapter(_name, _swapGasEstimate) {
address _quoteToken = IWooPP(_pool).quoteToken();
IERC20(_quoteToken).approve(_pool, UINT_MAX);
quoteToken = _quoteToken;
pool = _pool;
}
function setRebateCollector(address _rebateCollector) external onlyMaintainer {
rebateCollector = _rebateCollector;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_amountIn == 0) {
return 0;
}
if (_tokenIn == quoteToken) {
amountOut = _safeQuery(IWooPP(pool).querySellQuote, _tokenOut, _amountIn);
} else if (_tokenOut == quoteToken) {
amountOut = _safeQuery(IWooPP(pool).querySellBase, _tokenIn, _amountIn);
} else {
uint256 quoteAmount = _safeQuery(IWooPP(pool).querySellBase, _tokenIn, _amountIn);
amountOut = _safeQuery(IWooPP(pool).querySellQuote, _tokenOut, quoteAmount);
}
}
function _safeQuery(
function(address, uint256) external view returns (uint256) qFn,
address _baseToken,
uint256 _baseAmount
) internal view returns (uint256) {
try qFn(_baseToken, _baseAmount) returns (uint256 amountOut) {
return amountOut;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
_approveIfNeeded(_tokenIn, _amountIn);
uint256 realToAmount;
if (_tokenIn == quoteToken) {
realToAmount = IWooPP(pool).sellQuote(_tokenOut, _amountIn, _amountOut, _to, rebateCollector);
} else if (_tokenOut == quoteToken) {
realToAmount = IWooPP(pool).sellBase(_tokenIn, _amountIn, _amountOut, _to, rebateCollector);
} else {
uint256 quoteAmount = IWooPP(pool).sellBase(_tokenIn, _amountIn, 0, address(this), rebateCollector);
realToAmount = IWooPP(pool).sellQuote(_tokenOut, quoteAmount, _amountOut, _to, rebateCollector);
}
}
function _approveIfNeeded(address _tokenIn, uint256 _amount) internal {
uint256 allowance = IERC20(_tokenIn).allowance(address(this), pool);
if (allowance < _amount) {
IERC20(_tokenIn).approve(pool, UINT_MAX);
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IWooPPV2.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract WoofiV2Adapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable pool;
address public rebateCollector;
constructor(
string memory _name,
uint256 _swapGasEstimate,
address _pool
) SummitAdapter(_name, _swapGasEstimate) {
pool = _pool;
}
function setRebateCollector(address _rebateCollector) external onlyMaintainer {
rebateCollector = _rebateCollector;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256) {
if (_amountIn == 0) {
return 0;
}
try IWooPPV2(pool).query(_tokenIn, _tokenOut, _amountIn) returns (uint256 amountOut) {
return amountOut;
} catch {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
IERC20(_tokenIn).safeTransfer(pool, _amountIn);
IWooPPV2(pool).swap(_tokenIn, _tokenOut, _amountIn, _amountOut, _to, rebateCollector);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IxJOE.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract XJoeAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address public constant JOE = 0x6e84a6216eA6dACC71eE8E6b0a5B7322EEbC0fDd;
address public constant XJOE = 0x57319d41F71E81F3c65F2a47CA4e001EbAFd4F33;
constructor(uint256 _swapGasEstimate) SummitAdapter("XJoeAdapter", _swapGasEstimate) {
setAllowances();
}
function setAllowances() internal {
IERC20(XJOE).safeApprove(XJOE, UINT_MAX);
IERC20(JOE).safeApprove(XJOE, UINT_MAX);
}
function queryEnter(uint256 _amountIn) internal view returns (uint256) {
uint256 totalJoe = IERC20(JOE).balanceOf(XJOE);
uint256 totalShares = IxJOE(XJOE).totalSupply();
if (totalShares == 0 || totalJoe == 0) {
return _amountIn;
}
return (_amountIn * totalShares) / totalJoe;
}
function queryLeave(uint256 _amountIn) internal view returns (uint256) {
uint256 totalShares = IxJOE(XJOE).totalSupply();
return (_amountIn * IERC20(JOE).balanceOf(XJOE)) / totalShares;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_tokenIn == JOE && _tokenOut == XJOE) {
return queryEnter(_amountIn);
} else if (_tokenIn == XJOE && _tokenOut == JOE) {
return queryLeave(_amountIn);
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {
if (_tokenIn == JOE && _tokenOut == XJOE) {
IxJOE(XJOE).enter(_amountIn);
} else if (_tokenIn == XJOE && _tokenOut == JOE) {
IxJOE(XJOE).leave(_amountIn);
} else {
revert("XJoeAdapter: Unsupported token");
}
// Confidently transfer amount-out
_returnTo(_tokenOut, _amountOut, _to);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IYYDerivative.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract YYDerivativeAdapter is SummitAdapter {
using SafeERC20 for IERC20;
address public immutable derivative;
address public immutable underlying;
constructor(
string memory _name,
uint256 _swapGasEstimate,
address _derivative,
address _underlying
) SummitAdapter(_name, _swapGasEstimate) {
derivative = _derivative;
underlying = _underlying;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
if (_tokenIn == underlying && _tokenOut == derivative && IYYDerivative(derivative).depositsEnabled()) {
return _amountIn;
}
return 0;
}
function _swap(
uint256 _amountIn,
uint256, /*_amountOut*/
address _tokenIn,
address _tokenOut,
address _to
) internal override {
if (_tokenIn == underlying && _tokenOut == derivative) {
IERC20(underlying).approve(derivative, _amountIn);
IYYDerivative(derivative).deposit(_amountIn);
} else {
revert("YYDerivativeAdapter: Unsupported token");
}
// Confidently transfer amount-out
_returnTo(_tokenOut, _amountIn, _to);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IAdapter {
function name() external view returns (string memory);
function swapGasEstimate() external view returns (uint256);
function swap(
uint256,
uint256,
address,
address,
address
) external;
function query(
uint256,
address,
address
) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IPoolSwapStructs.sol";
interface IBasePool is IPoolSwapStructs {
function getPoolId() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.16;
interface IBlast {
enum GasMode {
VOID,
CLAIMABLE
}
function configureClaimableGas() external;
function configureGovernor(address governor) external;
function claimAllGas(
address contractAddress,
address recipientOfGas
) external returns (uint256);
function claimGasAtMinClaimRate(
address contractAddress,
address recipientOfGas,
uint256 minClaimRateBips
) external returns (uint256);
function claimMaxGas(
address contractAddress,
address recipientOfGas
) external returns (uint256);
function claimGas(
address contractAddress,
address recipientOfGas,
uint256 gasToClaim,
uint256 gasSecondsToConsume
) external returns (uint256);
function readGasParams(
address contractAddress
)
external
view
returns (
uint256 etherSeconds,
uint256 etherBalance,
uint256 lastUpdated,
GasMode
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICurve1 {
function underlying_coins(uint256 index) external view returns (address);
function exchange_underlying(
uint256 tokenIndexFrom,
uint256 tokenIndexTo,
uint256 dx,
uint256 minDy
) external;
function get_dy_underlying(
uint256 tokenIndexFrom,
uint256 tokenIndexTo,
uint256 dx
) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICurve2 {
function underlying_coins(uint256 index) external view returns (address);
function get_dy_underlying(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx
) external view returns (uint256);
function exchange_underlying(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx,
uint256 minDy
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICurveMeta {
function base_coins(uint256) external view returns (address);
function coins(uint256 index) external view returns (address);
function get_dy_underlying(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx
) external view returns (uint256);
function exchange_underlying(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx,
uint256 minDy
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICurvePlain128 {
function coins(uint256 index) external view returns (address);
function exchange(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx,
uint256 minDy
) external returns (uint256);
function get_dy(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx
) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICurvePlain128Native {
function coins(uint256 index) external view returns (address);
function exchange(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx,
uint256 minDy
) external payable returns (uint256);
function get_dy(
int128 tokenIndexFrom,
int128 tokenIndexTo,
uint256 dx
) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICurvePlain256 {
function coins(uint256 index) external view returns (address);
function exchange(
uint256 tokenIndexFrom,
uint256 tokenIndexTo,
uint256 dx,
uint256 minDy
) external;
function get_dy(
uint256 tokenIndexFrom,
uint256 tokenIndexTo,
uint256 dx
) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IDodoHelper {
function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
}
interface IDodoV1 {
function _QUOTE_TOKEN_() external view returns (address);
function _BASE_TOKEN_() external view returns (address);
function querySellBaseToken(uint256 amount) external view returns (uint256);
function queryBuyBaseToken(uint256 amount) external view returns (uint256);
function sellBaseToken(
uint256 amount,
uint256 minReceiveQuote,
bytes calldata data
) external returns (uint256);
function buyBaseToken(
uint256 amount,
uint256 maxPayQuote,
bytes calldata data
) external returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IDodoV2 {
function _QUOTE_TOKEN_() external view returns (address);
function _BASE_TOKEN_() external view returns (address);
function querySellBase(address trader, uint256 payBaseAmount) external view returns (uint256 receiveQuoteAmount);
function querySellQuote(address trader, uint256 payQuoteAmount) external view returns (uint256 receiveBaseAmount);
function sellBase(address to) external returns (uint256 receiveQuoteAmount);
function sellQuote(address to) external returns (uint256 receiveBaseAmount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20 {
event Approval(address, address, uint256);
event Transfer(address, address, uint256);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function transferFrom(
address,
address,
uint256
) external returns (bool);
function allowance(address, address) external view returns (uint256);
function approve(address, uint256) external returns (bool);
function transfer(address, uint256) external returns (bool);
function balanceOf(address) external view returns (uint256);
function nonces(address) external view returns (uint256); // Only tokens that support permit
function permit(
address,
address,
uint256,
uint256,
uint8,
bytes32,
bytes32
) external; // Only tokens that support permit
function swap(address, uint256) external; // Only Avalanche bridge tokens
function swapSupply(address) external view returns (uint256); // Only Avalanche bridge tokens
function totalSupply() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// @note: operator stands for interface address
interface IgAVAX {
function setApprovalForAll(address operator, bool approved) external;
function pricePerShare(uint256 _id) external view returns (uint256);
function balanceOf(address account, uint256 id) external view returns (uint256);
function isInterface(address operator, uint256 id) external view returns (bool);
function isApprovedForAll(address account, address operator) external view returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IGenericFactory {
function allPairs() external view returns (address[] memory);
function getPair(address tokenA, address tokenB, uint256 curveId) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IGeodePortal {
function gAVAX() external view returns (address);
function getNameFromId(uint256 _id) external view returns (bytes memory);
function planetCurrentInterface(uint256 _id) external view returns (address);
function planetWithdrawalPool(uint256 _id) external view returns (address);
function getMaintainerFromId(uint256) external view returns (address);
function isStakingPausedForPool(uint256) external view returns (bool);
function unpauseStakingForPool(uint256) external;
function pauseStakingForPool(uint256) external;
function stake(
uint256 planetId,
uint256 minGavax,
uint256 deadline
) external payable returns (uint256 totalgAvax);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IGeodeWP {
function paused() external view returns (bool);
function getDebt() external view returns (uint256);
function getToken() external view returns (uint256);
function getERC1155() external view returns (address);
function getTokenBalance(uint8) external view returns (uint256);
function calculateSwap(
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx
) external view returns (uint256);
function swap(
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx,
uint256 minDy,
uint256 deadline
) external payable returns (uint256);
function addLiquidity(
uint256[] calldata amounts,
uint256 minToMint,
uint256 deadline
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IGlpManager {
function getAumInUsdg(bool maximise) external view returns (uint256);
function vault() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IGmxRewardRouter {
function glpManager() external view returns (address);
function mintAndStakeGlp(
address _token,
uint256 _amount,
uint256 _minUsdg,
uint256 _minGlp
) external returns (uint256);
function unstakeAndRedeemGlp(
address _tokenOut,
uint256 _glpAmount,
uint256 _minOut,
address _receiver
) external returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IGmxVaultPriceFeed {
function getPrice(address, bool, bool, bool) external view returns (uint256);
}
interface IGmxVaultUtils {
function getSwapFeeBasisPoints(address, address, uint256) external view returns (uint256);
function getBuyUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
function getSellUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
}
interface IGmxVault {
function swap(address, address, address) external;
function whitelistedTokens(address) external view returns (bool);
function isSwapEnabled() external view returns (bool);
function vaultUtils() external view returns (IGmxVaultUtils);
function priceFeed() external view returns (IGmxVaultPriceFeed);
function allWhitelistedTokensLength() external view returns (uint256);
function allWhitelistedTokens(uint256) external view returns (address);
function maxUsdgAmounts(address) external view returns (uint256);
function usdgAmounts(address) external view returns (uint256);
function reservedAmounts(address) external view returns (uint256);
function bufferAmounts(address) external view returns (uint256);
function poolAmounts(address) external view returns (uint256);
function usdg() external view returns (address);
function hasDynamicFees() external view returns (bool);
function stableTokens(address) external view returns (bool);
function getFeeBasisPoints(address, uint256, uint256, uint256, bool) external view returns (uint256);
function stableSwapFeeBasisPoints() external view returns (uint256);
function swapFeeBasisPoints() external view returns (uint256);
function stableTaxBasisPoints() external view returns (uint256);
function taxBasisPoints() external view returns (uint256);
function mintBurnFeeBasisPoints() external view returns (uint256);
function setBufferAmount(address, uint256) external;
function gov() external view returns (address);
function getMaxPrice(address _token) external view returns (uint256);
function getMinPrice(address _token) external view returns (uint256);
function adjustForDecimals(uint256 _amount, address _tokenDiv, address _tokenMul) external view returns (uint256);
function getRedemptionAmount(address _token, uint256 _usdgAmount) external view returns (uint256);
function getTargetUsdgAmount(address _token) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IKyberPool {
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;
function getTradeInfo()
external
view
returns (
uint112 _vReserve0,
uint112 _vReserve1,
uint112 reserve0,
uint112 reserve1,
uint256 feeInPrecision
);
function token0() external view returns (address);
function token1() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ILBPair {
function getTokenX() external view returns (address);
function getTokenY() external view returns (address);
function swap(bool swapForY, address to) external returns (bytes32 amountsOut);
function getSwapOut(uint128 amountIn, bool swapForY)
external
view
returns (uint128 amountInLeft, uint128 amountOut, uint128 fee);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ILBFactory {
struct LBPairInformation {
uint24 binStep;
address LBPair;
bool createdByOwner;
bool ignoredForRouting;
}
function getAllLBPairs(address tokenX, address tokenY)
external
view
returns (LBPairInformation[] memory LBPairsBinStep);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ILBPair {
function tokenX() external view returns (address);
function tokenY() external view returns (address);
function swap(bool sentTokenY, address to) external returns (uint256 amountXOut, uint256 amountYOut);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ILBRouter {
function factory() external view returns (address);
function getSwapOut(
address pair,
uint256 amountIn,
bool swapForY
) external view returns (uint256 amountOut, uint256 feesIn);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
uint256[] memory pairBinSteps,
address[] memory tokenPath,
address to,
uint256 deadline
) external returns (uint256 amountOut);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IBasePool.sol";
interface IMinimalSwapInfoPool is IBasePool {
function onSwap(
SwapRequest memory swapRequest,
uint256 currentBalanceTokenIn,
uint256 currentBalanceTokenOut
) external view returns (uint256 amount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20.sol";
interface ImSUMMIT is IERC20 {
function unmoon(uint256, address) external;
function moon(uint256, address) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPlatypus {
// Views
function quotePotentialSwap(
address fromToken,
address totoken,
uint256 fromAmount
) external view returns (uint256 potentialOutcome); // Second arg (haircut) is not used
function getTokenAddresses() external view returns (address[] memory);
function paused() external view returns (bool);
// Modifiers
function swap(
address fromToken,
address toToken,
uint256 fromAmount,
uint256 minAmountOut,
address to,
uint256 deadline
) external;
function pause() external;
function unpause() external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IVault.sol";
interface IPoolSwapStructs {
struct SwapRequest {
IVault.SwapKind kind;
IERC20 tokenIn;
IERC20 tokenOut;
uint256 amount;
bytes32 poolId;
uint256 lastChangeBlock;
address from;
address to;
bytes userData;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IReservoirPair {
function token0() external returns (address);
function token1() external returns (address);
function swap(int256 aAmount, bool aExactIn, address aTo, bytes calldata aData)
external
returns (uint256 rAmountOut);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IQuoter {
/// @dev aPath array of ERC20 tokens to swap into
function getAmountsOut(uint256 aAmountIn, address[] calldata aPath, uint256[] calldata aCurveIds)
external
view
returns (uint256[] memory rAmountsOut);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20.sol";
interface ISaddle {
function getTokenIndex(address tokenAddress) external view returns (uint8);
function getTokenBalance(uint8 index) external view returns (uint256);
function getToken(uint8 index) external view returns (address);
function getVirtualPrice() external view returns (uint256);
function owner() external view returns (address);
function paused() external view returns (bool);
function calculateSwap(
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx
) external view returns (uint256);
function unpause() external;
function pause() external;
function swap(
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx,
uint256 minDy,
uint256 deadline
) external returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20.sol";
struct SwapStorage {
uint256 initialA;
uint256 futureA;
uint256 initialATime;
uint256 futureATime;
uint256 swapFee;
uint256 adminFee;
address lpToken;
}
interface ISaddleMeta {
function getToken(uint8 index) external view returns (address);
function getVirtualPrice() external view returns (uint256);
function owner() external view returns (address);
function paused() external view returns (bool);
function calculateSwapUnderlying(
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx
) external view returns (uint256);
function unpause() external;
function pause() external;
function swapUnderlying(
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx,
uint256 minDy,
uint256 deadline
) external returns (uint256);
function metaSwapStorage() external returns (address);
function swapStorage() external returns (SwapStorage memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20.sol";
interface ISAVAX is IERC20 {
function getSharesByPooledAvax(uint256) external view returns (uint256);
function submit() external payable returns (uint256);
function mintingPaused() external view returns (bool);
function totalPooledAvax() external view returns (uint256);
function totalPooledAvaxCap() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IStabilityFund {
function swap(
address token0,
uint256 amount,
address token1
) external;
function swapEnabled() external view returns (bool);
function isStableToken(address) external view returns (bool);
function isTokenDisabled(address) external view returns (bool);
function getStableTokens() external view returns (address[] memory);
function getStableTokensCount() external view returns (uint256);
function swapFee() external view returns (uint256);
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
interface ISummitPoints {
event UpdatedVolumeAdapter(address indexed _volumeAdapter);
event UpdatedReferralsContract(address indexed _referrals);
event UpdatedGlobalBoost(uint256 _boost);
event UpdatedVolumeScalers(uint256 _refVolumeScaler, uint256 _adapterVolumeScaler);
event UpdatedBlacklisted(address _add,bool _blacklisted);
event AddedUserVolume(address indexed _user, uint256 _volume);
event AddedReferrerVolume(address indexed _referrer, address indexed _user, uint256 _volume);
event AddedAdapterVolume(address indexed _adapter, uint256 _volume);
event TransferredVolume(address indexed _caller, address indexed _from, address indexed _to, uint256 _selfVolume, uint256 _refVolume, uint256 _adapterVolume);
event UpdatedDelegate(address indexed _caller, address indexed _user, address indexed _delegate);
event UpdatedAdapterDelegate(address indexed _adapter, address indexed _delegate);
event SummitTeamGivenPoints(address indexed _user, uint256 _volume);
function setVolumeAdapter(address _volumeAdapter) external;
function setReferralsContract(address _referrals) external;
function setGlobalBoost(uint256 _boost) external;
function setBlacklisted(address _add, bool _blacklisted) external;
function summitTeamGivePoints(address _add, uint256 _volume) external;
function setVolumeScalers(uint256 _refVolumeScaler, uint256 _adapterVolumeScaler) external;
function setDelegate(address _user, address _delegate) external;
function setAdapterDelegate(address _adapter, address _delegate) external;
function addVolume(address _add, uint256 _volume) external;
function addAdapterVolume(address _adapter, uint256 _volume) external;
function transferVolume(address _from, address _to, uint256 _selfVolume, uint256 _refVolume, uint256 _adapterVolume) external;
function getVolume(address _add) external view returns (uint256 selfVolume, uint256 refVolume, uint256 adapterVolume);
function getPoints(address _add) external view returns (uint256 pointsFromSelf, uint256 pointsFromRef, uint256 pointsFromAdapter, uint256 pointsTotal);
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISummitReferrals {
event UpdatedPointsContract(address indexed _pointsContract);
event BoostedReferrer(address indexed referrer, uint8 _boostLevel);
event BoostedReferrers(address[] referrer, uint8[] _boostLevel);
event UpdatedReferrer(address indexed _add, address indexed _referrer);
event UpdatedLevelData(uint256[] _refPointsReq, uint256[] _selfPointsReq, uint256[] _refsReq, uint256[] _multRew, uint256 _hasReferrerBonusMult);
event UpdatedReferralCode(address indexed _caller, address indexed _user, string _code);
function setPointsContract(address _pointsContract) external;
function setReferrer(address _referrer, string memory _code) external;
function setReferralCode(string memory _code) external;
function maintainerSetReferralCode(address _add, string memory _code) external;
function boostReferrer(address _referrer, uint8 _boostLevel) external;
function boostReferrers(address[] memory _referrers, uint8[] memory _boostLevels) external;
function setLevelData(uint256[] memory _refPointsReq, uint256[] memory _selfPointsReq, uint256[] memory _refsReq, uint256[] memory _multRew, uint256 _hasReferrerBonusMult) external;
function getReferrer(address _add) external view returns (address);
function getReferrerCode(address _add) external view returns (string memory);
function getRefsCount(address _add) external view returns (uint256);
function getReferrerLevelWithoutBoost(address _add) external view returns (uint8);
function getReferrerLevel(address _add) external view returns (uint8);
function getLevelRequirements(uint8 _level) external view returns (uint256 selfVolume, uint256 refVolume, uint256 refsCount);
function getUserNextLevelRequirements(address _add) external view returns (uint256 selfVolume, uint256 refVolume, uint256 refsCount);
function getRefVolumeBonusMultiplier(address _add) external view returns (uint256);
function getSelfVolumeMultiplier(address _add) external view returns (uint256);
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
struct Query {
address adapter;
address tokenIn;
address tokenOut;
uint256 amountOut;
}
struct Offer {
bytes amounts;
bytes adapters;
bytes path;
uint256 gasEstimate;
}
struct FormattedOffer {
uint256[] amounts;
address[] adapters;
address[] path;
uint256 gasEstimate;
}
struct Trade {
uint256 amountIn;
uint256 amountOut;
address[] path;
address[] adapters;
}
interface ISummitRouter {
event UpdatedTrustedTokens(address[] _newTrustedTokens);
event UpdatedTokenVolumeMultipliers(address[] _tokens, uint256[] _pointMultipliers);
event UpdatedTokenBonusMultipliers(address [] _tokens, uint256[] _multipliers);
event UpdatedAdapters(address[] _newAdapters);
event UpdatedVolumeAdapter(address _volumeAdapter);
event UpdatedMinFee(uint256 _oldMinFee, uint256 _newMinFee);
event UpdatedFeeClaimer(address _oldFeeClaimer, address _newFeeClaimer);
event SummitSwap(address indexed _tokenIn, address indexed _tokenOut, uint256 _amountIn, uint256 _amountOut);
// admin
function setTrustedTokens(address[] memory _trustedTokens) external;
function setAdapters(address[] memory _adapters) external;
function setVolumeAdapter(address _volumeAdapter) external;
function setFeeClaimer(address _claimer) external;
function setMinFee(uint256 _fee) external;
// misc
function trustedTokensCount() external view returns (uint256);
function adaptersCount() external view returns (uint256);
function getTokenBonus(address _token) external view returns (uint256);
// query
function queryAdapter(
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
uint8 _index
) external returns (uint256);
function queryNoSplit(
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
uint8[] calldata _options
) external view returns (Query memory);
function queryNoSplit(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) external view returns (Query memory);
function findBestPathWithGas(
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
uint256 _maxSteps,
uint256 _gasPrice
) external view returns (FormattedOffer memory);
function findBestPath(
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
uint256 _maxSteps
) external view returns (FormattedOffer memory);
// swap
function swapNoSplit(
Trade calldata _trade,
address _to,
uint256 _fee
) external;
function swapNoSplitFromNATIVE(
Trade calldata _trade,
address _to,
uint256 _fee
) external payable;
function swapNoSplitToNATIVE(
Trade calldata _trade,
address _to,
uint256 _fee
) external;
function swapNoSplitWithPermit(
Trade calldata _trade,
address _to,
uint256 _fee,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) external;
function swapNoSplitToNATIVEWithPermit(
Trade calldata _trade,
address _to,
uint256 _fee,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) external;
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISummitVolumeAdapter {
event UpdatedRouter(address indexed _router);
event UpdatedPointsContract(address indexed _pointsContract);
function addVolume(address _add, uint256 _volume) external;
function addAdapterVolume(address _adapter, uint256 _volume) external;
function setRouter(address _router) external;
function setPointsContract(address _pointsContract) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapFactory {
function getPair(address tokenA, address tokenB) external view returns (address pair);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapPair {
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
);
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20.sol";
interface IVault {
enum SwapKind {
GIVEN_IN,
GIVEN_OUT
}
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
address assetIn;
address assetOut;
uint256 amount;
bytes userData;
}
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
function swap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) external payable returns (uint256);
function getPoolTokens(bytes32 poolId)
external
view
returns (
IERC20[] memory tokens,
uint256[] memory balances,
uint256 lastChangeBlock
);
struct BatchSwapStep {
bytes32 poolId;
uint256 assetInIndex;
uint256 assetOutIndex;
uint256 amount;
bytes userData;
}
function queryBatchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
address[] memory assets,
FundManagement memory funds
) external returns (int256[] memory assetDeltas);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20.sol";
interface IWETH is IERC20 {
function withdraw(uint256 amount) external;
function deposit() external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IWombat {
// Views
function quotePotentialSwap(
address fromToken,
address totoken,
int256 fromAmount
) external view returns (uint256 potentialOutcome); // Second arg (haircut) is not used
function getTokens() external view returns (address[] memory);
function paused() external view returns (bool);
// Modifiers
function swap(
address fromToken,
address toToken,
uint256 fromAmount,
uint256 minAmountOut,
address to,
uint256 deadline
) external;
function pause() external;
function unpause() external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IWooPP {
function quoteToken() external view returns (address);
function querySellQuote(address, uint256) external view returns (uint256);
function querySellBase(address, uint256) external view returns (uint256);
function sellBase(
address baseToken,
uint256 baseAmount,
uint256 minQuoteAmount,
address to,
address rebateTo
) external returns (uint256 quoteAmount);
function sellQuote(
address baseToken,
uint256 quoteAmount,
uint256 minBaseAmount,
address to,
address rebateTo
) external returns (uint256 baseAmount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IWooPPV2 {
/// @notice The quote token address (immutable).
/// @return address of quote token
function quoteToken() external view returns (address);
/// @notice Gets the pool size of the specified token (swap liquidity).
/// @param token the token address
/// @return the pool size
function poolSize(address token) external view returns (uint256);
/// @notice Query the amount to swap `fromToken` to `toToken`, without checking the pool reserve balance.
/// @param fromToken the from token
/// @param toToken the to token
/// @param fromAmount the amount of `fromToken` to swap
/// @return toAmount the swapped amount of `toToken`
function tryQuery(
address fromToken,
address toToken,
uint256 fromAmount
) external view returns (uint256 toAmount);
/// @notice Query the amount to swap `fromToken` to `toToken`, with checking the pool reserve balance.
/// @dev tx reverts when 'toToken' balance is insufficient.
/// @param fromToken the from token
/// @param toToken the to token
/// @param fromAmount the amount of `fromToken` to swap
/// @return toAmount the swapped amount of `toToken`
function query(
address fromToken,
address toToken,
uint256 fromAmount
) external view returns (uint256 toAmount);
/// @notice Swap `fromToken` to `toToken`.
/// @param fromToken the from token
/// @param toToken the to token
/// @param fromAmount the amount of `fromToken` to swap
/// @param minToAmount the minimum amount of `toToken` to receive
/// @param to the destination address
/// @param rebateTo the rebate address (optional, can be address ZERO)
/// @return realToAmount the amount of toToken to receive
function swap(
address fromToken,
address toToken,
uint256 fromAmount,
uint256 minToAmount,
address to,
address rebateTo
) external returns (uint256 realToAmount);
/// @notice Deposit the specified token into the liquidity pool of WooPPV2.
/// @param token the token to deposit
/// @param amount the deposit amount
function deposit(address token, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IxJOE {
function leave(uint256) external;
function enter(uint256) external;
function totalSupply() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IYYDerivative {
function deposit(uint256 amount) external;
function depositsEnabled() external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
/**
* @dev Contract module which extends the basic access control mechanism of Ownable
* to include many maintainers, whom only the owner (DEFAULT_ADMIN_ROLE) may add and
* remove.
*
* By default, the owner account will be the one that deploys the contract. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available this modifier:
* `onlyMaintainer`, which can be applied to your functions to restrict their use to
* the accounts with the role of maintainer.
*/
abstract contract Maintainable is AccessControl {
bytes32 public constant MAINTAINER_ROLE = keccak256("MAINTAINER_ROLE");
constructor() {
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(MAINTAINER_ROLE, msg.sender);
}
function addMaintainer(address addedMaintainer) public virtual {
grantRole(MAINTAINER_ROLE, addedMaintainer);
}
function removeMaintainer(address removedMaintainer) public virtual {
revokeRole(MAINTAINER_ROLE, removedMaintainer);
}
function renounceRole(bytes32 role) public virtual {
renounceRole(role, msg.sender);
}
function transferOwnership(address newOwner) public virtual {
grantRole(DEFAULT_ADMIN_ROLE, newOwner);
renounceRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
modifier onlyMaintainer() {
require(hasRole(MAINTAINER_ROLE, msg.sender), "Maintainable: Caller is not a maintainer");
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import "./SafeERC20.sol";
import "./Maintainable.sol";
abstract contract Recoverable is Maintainable {
using SafeERC20 for IERC20;
event Recovered(
address indexed _asset,
uint amount
);
/**
* @notice Recover ERC20 from contract
* @param _tokenAddress token address
* @param _tokenAmount amount to recover
*/
function recoverERC20(address _tokenAddress, uint _tokenAmount) external onlyMaintainer {
require(_tokenAmount > 0, "Nothing to recover");
IERC20(_tokenAddress).safeTransfer(msg.sender, _tokenAmount);
emit Recovered(_tokenAddress, _tokenAmount);
}
/**
* @notice Recover native asset from contract
* @param _amount amount
*/
function recoverNATIVE(uint _amount) external onlyMaintainer {
require(_amount > 0, "Nothing to recover");
payable(msg.sender).transfer(_amount);
emit Recovered(address(0), _amount);
}
}// This is a simplified version of OpenZepplin's SafeERC20 library
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "../interface/IERC20.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
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 {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
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));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >=0.8.4;
import { Offer, FormattedOffer } from "../interface/ISummitRouter.sol";
import "./TypeConversion.sol";
library OfferUtils {
using TypeConversion for address;
using TypeConversion for uint256;
using TypeConversion for bytes;
function newOffer(
uint _amountIn,
address _tokenIn
) internal pure returns (Offer memory offer) {
offer.amounts = _amountIn.toBytes();
offer.path = _tokenIn.toBytes();
}
/**
* Makes a deep copy of Offer struct
*/
function clone(Offer memory _queries) internal pure returns (Offer memory) {
return Offer(_queries.amounts, _queries.adapters, _queries.path, _queries.gasEstimate);
}
/**
* Appends new elements to the end of Offer struct
*/
function addToTail(
Offer memory _queries,
uint256 _amount,
address _adapter,
address _tokenOut,
uint256 _gasEstimate
) internal pure {
_queries.path = bytes.concat(_queries.path, _tokenOut.toBytes());
_queries.adapters = bytes.concat(_queries.adapters, _adapter.toBytes());
_queries.amounts = bytes.concat(_queries.amounts, _amount.toBytes());
_queries.gasEstimate += _gasEstimate;
}
/**
* Formats elements in the Offer object from byte-arrays to integers and addresses
*/
function format(Offer memory _queries) internal pure returns (FormattedOffer memory) {
return
FormattedOffer(
_queries.amounts.toUints(),
_queries.adapters.toAddresses(),
_queries.path.toAddresses(),
_queries.gasEstimate
);
}
function getTokenOut(
Offer memory _offer
) internal pure returns (address tokenOut) {
tokenOut = _offer.path.toAddress(_offer.path.length); // Last 32 bytes
}
function getAmountOut(
Offer memory _offer
) internal pure returns (uint amountOut) {
amountOut = _offer.amounts.toUint(_offer.path.length); // Last 32 bytes
}
}
library FormattedOfferUtils {
using TypeConversion for address;
using TypeConversion for uint256;
using TypeConversion for bytes;
/**
* Appends new elements to the end of FormattedOffer
*/
function addToTail(
FormattedOffer memory offer,
uint256 amountOut,
address wrapper,
address tokenOut,
uint256 gasEstimate
) internal pure {
offer.amounts = bytes.concat(abi.encodePacked(offer.amounts), amountOut.toBytes()).toUints();
offer.adapters = bytes.concat(abi.encodePacked(offer.adapters), wrapper.toBytes()).toAddresses();
offer.path = bytes.concat(abi.encodePacked(offer.path), tokenOut.toBytes()).toAddresses();
offer.gasEstimate += gasEstimate;
}
/**
* Appends new elements to the beginning of FormattedOffer
*/
function addToHead(
FormattedOffer memory offer,
uint256 amountOut,
address wrapper,
address tokenOut,
uint256 gasEstimate
) internal pure {
offer.amounts = bytes.concat(amountOut.toBytes(), abi.encodePacked(offer.amounts)).toUints();
offer.adapters = bytes.concat(wrapper.toBytes(), abi.encodePacked(offer.adapters)).toAddresses();
offer.path = bytes.concat(tokenOut.toBytes(), abi.encodePacked(offer.path)).toAddresses();
offer.gasEstimate += gasEstimate;
}
function getAmountOut(FormattedOffer memory offer) internal pure returns (uint256) {
return offer.amounts[offer.amounts.length - 1];
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
library TypeConversion {
function toBytes12(address x) internal pure returns (bytes12 y) {
assembly { y := x }
}
function toBytes32(address x) internal pure returns (bytes32 y) {
assembly { y := x }
}
function toAddress(bytes32 x) internal pure returns (address y) {
assembly { y := x }
}
function toBytes(address x) internal pure returns (bytes memory y) {
y = new bytes(32);
assembly { mstore(add(y, 32), x) }
}
function toBytes(bytes32 x) internal pure returns (bytes memory y) {
y = new bytes(32);
assembly { mstore(add(y, 32), x) }
}
function toBytes(uint x) internal pure returns (bytes memory y) {
y = new bytes(32);
assembly { mstore(add(y, 32), x) }
}
function toAddress(
bytes memory x,
uint offset
) internal pure returns (address y) {
assembly { y := mload(add(x, offset)) }
}
function toUint(
bytes memory x,
uint offset
) internal pure returns (uint y) {
assembly { y := mload(add(x, offset)) }
}
function toBytes12(
bytes memory x,
uint offset
) internal pure returns (bytes12 y) {
assembly { y := mload(add(x, offset)) }
}
function toBytes32(
bytes memory x,
uint offset
) internal pure returns (bytes32 y) {
assembly { y := mload(add(x, offset)) }
}
function toAddresses(
bytes memory xs
) internal pure returns (address[] memory ys) {
ys = new address[](xs.length/32);
for (uint i=0; i < xs.length/32; i++) {
ys[i] = toAddress(xs, i*32 + 32);
}
}
function toUints(
bytes memory xs
) internal pure returns (uint[] memory ys) {
ys = new uint[](xs.length/32);
for (uint i=0; i < xs.length/32; i++) {
ys[i] = toUint(xs, i*32 + 32);
}
}
function toBytes32s(
bytes memory xs
) internal pure returns (bytes32[] memory ys) {
ys = new bytes32[](xs.length/32);
for (uint i=0; i < xs.length/32; i++) {
ys[i] = toBytes32(xs, i*32 + 32);
}
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "./interface/IERC20.sol";
import "./interface/IBlast.sol";
import "./lib/SafeERC20.sol";
import "./lib/Maintainable.sol";
abstract contract SummitAdapter is Maintainable {
using SafeERC20 for IERC20;
uint256 internal constant UINT_MAX = type(uint256).max;
uint256 public swapGasEstimate;
string public name;
event SummitAdapterSwap(address indexed _tokenFrom, address indexed _tokenTo, uint256 _amountIn, uint256 _amountOut);
event UpdatedGasEstimate(address indexed _adapter, uint256 _newEstimate);
event Recovered(address indexed _asset, uint256 amount);
error AlreadyInitialized();
constructor(string memory _name, uint256 _gasEstimate) {
setName(_name);
setSwapGasEstimate(_gasEstimate);
}
bool public initialized = false;
address public governor;
function initialize(address _governor) public onlyMaintainer {
if (initialized) revert AlreadyInitialized();
initialized = true;
IBlast blast = IBlast(0x4300000000000000000000000000000000000002);
blast.configureClaimableGas();
blast.configureGovernor(_governor);
governor = _governor;
}
function setName(string memory _name) internal {
require(bytes(_name).length != 0, "Invalid adapter name");
name = _name;
}
function setSwapGasEstimate(uint256 _estimate) public onlyMaintainer {
require(_estimate != 0, "Invalid gas-estimate");
swapGasEstimate = _estimate;
emit UpdatedGasEstimate(address(this), _estimate);
}
function revokeAllowance(address _token, address _spender) external onlyMaintainer {
IERC20(_token).safeApprove(_spender, 0);
}
function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external onlyMaintainer {
require(_tokenAmount > 0, "SummitAdapter: Nothing to recover");
IERC20(_tokenAddress).safeTransfer(msg.sender, _tokenAmount);
emit Recovered(_tokenAddress, _tokenAmount);
}
function recoverAVAX(uint256 _amount) external onlyMaintainer {
require(_amount > 0, "SummitAdapter: Nothing to recover");
payable(msg.sender).transfer(_amount);
emit Recovered(address(0), _amount);
}
function query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) external view returns (uint256) {
return _query(_amountIn, _tokenIn, _tokenOut);
}
function swap(
uint256 _amountIn,
uint256 _amountOut,
address _fromToken,
address _toToken,
address _to
) external virtual {
uint256 toBal0 = IERC20(_toToken).balanceOf(_to);
_swap(_amountIn, _amountOut, _fromToken, _toToken, _to);
uint256 diff = IERC20(_toToken).balanceOf(_to) - toBal0;
require(diff >= _amountOut, "Insufficient amount-out");
emit SummitAdapterSwap(_fromToken, _toToken, _amountIn, _amountOut);
}
function _returnTo(
address _token,
uint256 _amount,
address _to
) internal {
if (address(this) != _to) IERC20(_token).safeTransfer(_to, _amount);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _fromToken,
address _toToken,
address _to
) internal virtual;
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view virtual returns (uint256);
receive() external payable {}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "./interface/ISummitPoints.sol";
import "./interface/ISummitReferrals.sol";
import "./interface/IBlast.sol";
import "./lib/Maintainable.sol";
import "./lib/SummitViewUtils.sol";
import "./lib/Recoverable.sol";
contract SummitPoints is Maintainable, Recoverable, ISummitPoints {
address public VOLUME_ADAPTER;
address public REFERRALS;
mapping(address => uint256) public SELF_VOLUME;
mapping(address => uint256) public REF_VOLUME;
mapping(address => uint256) public ADAPTER_VOLUME;
mapping(address => address) public DELEGATE;
mapping(address => bool) public BLACKLISTED;
uint256 public GLOBAL_BOOST = 0;
uint256 public BASE_VOLUME_SCALER = 100; // 1% (1 point per $100 in volume initially)
uint256 public REF_VOLUME_SCALER = 0;
uint256 public ADAPTER_VOLUME_SCALER = 200; // 2%
error AlreadyInitialized();
error ZeroAddress();
error NotPermitted();
error InvalidSelfAmount();
error InvalidRefAmount();
error InvalidAdapterAmount();
bool public initialized = false;
address public governor;
function initialize(address _governor) public onlyMaintainer {
if (initialized) revert AlreadyInitialized();
initialized = true;
IBlast blast = IBlast(0x4300000000000000000000000000000000000002);
blast.configureClaimableGas();
blast.configureGovernor(_governor);
governor = _governor;
}
function setVolumeAdapter(address _volumeAdapter) override public onlyMaintainer {
emit UpdatedVolumeAdapter(_volumeAdapter);
VOLUME_ADAPTER = _volumeAdapter;
}
function setReferralsContract(address _referrals) override public onlyMaintainer {
emit UpdatedReferralsContract(_referrals);
REFERRALS = _referrals;
}
function setVolumeScalers(uint256 _refVolumeScaler, uint256 _adapterVolumeScaler) override public onlyMaintainer {
REF_VOLUME_SCALER = _refVolumeScaler;
ADAPTER_VOLUME_SCALER = _adapterVolumeScaler;
emit UpdatedVolumeScalers(_refVolumeScaler, _adapterVolumeScaler);
}
function setAdapterDelegate(address _adapter, address _delegate) override public onlyMaintainer {
DELEGATE[_adapter] = _delegate;
emit UpdatedAdapterDelegate(_adapter, _delegate);
}
function setGlobalBoost(uint256 _boost) override public onlyMaintainer {
GLOBAL_BOOST = _boost;
emit UpdatedGlobalBoost(_boost);
}
function setBlacklisted(address _add, bool _blacklisted) override public onlyMaintainer {
BLACKLISTED[_add] = _blacklisted;
emit UpdatedBlacklisted(_add, _blacklisted);
}
function setDelegate(address _user, address _delegate) override public {
if (_user != msg.sender && DELEGATE[_user] != msg.sender) revert NotPermitted();
DELEGATE[msg.sender] = _delegate;
emit UpdatedDelegate(msg.sender, _user, _delegate);
}
function summitTeamGivePoints(address _add, uint256 _volume) override public onlyMaintainer {
SELF_VOLUME[_add] += _volume;
emit SummitTeamGivenPoints(_add, _volume);
}
function addVolume(address _add, uint256 _volume) override public {
if (msg.sender != VOLUME_ADAPTER) revert NotPermitted();
if (GLOBAL_BOOST > 0) {
_volume = (_volume * (10000 + GLOBAL_BOOST)) / 10000;
}
SELF_VOLUME[_add] += _volume;
emit AddedUserVolume(_add, _volume);
address referrer = REFERRALS == address(0) ? address(0) : ISummitReferrals(REFERRALS).getReferrer(_add);
if (referrer != address(0)) {
REF_VOLUME[referrer] += _volume;
emit AddedReferrerVolume(referrer, _add, _volume);
}
}
function addAdapterVolume(address _adapter, uint256 _volume) override public {
if (msg.sender != VOLUME_ADAPTER) revert NotPermitted();
if (GLOBAL_BOOST > 0) {
_volume = (_volume * (10000 + GLOBAL_BOOST)) / 10000;
}
ADAPTER_VOLUME[_adapter] += _volume;
emit AddedAdapterVolume(_adapter, _volume);
}
function transferVolume(address _from, address _to, uint256 _selfAmount, uint256 _refAmount, uint256 _adapterAmount) override public {
if (_to == address(0)) revert ZeroAddress();
if (_from != msg.sender && DELEGATE[_from] != msg.sender) revert NotPermitted();
if (_selfAmount > SELF_VOLUME[_from]) revert InvalidSelfAmount();
if (_refAmount > REF_VOLUME[_from]) revert InvalidRefAmount();
if (_adapterAmount > ADAPTER_VOLUME[_from]) revert InvalidAdapterAmount();
SELF_VOLUME[_from] -= _selfAmount;
SELF_VOLUME[_to] += _selfAmount;
REF_VOLUME[_from] -= _refAmount;
REF_VOLUME[_to] += _refAmount;
ADAPTER_VOLUME[_from] -= _adapterAmount;
ADAPTER_VOLUME[_to] += _adapterAmount;
emit TransferredVolume(msg.sender, _from, _to, _selfAmount, _refAmount, _adapterAmount);
}
function getVolume(address _add) override public view returns (uint256 selfVolume, uint256 refVolume, uint256 adapterVolume) {
return (
SELF_VOLUME[_add],
REF_VOLUME[_add],
ADAPTER_VOLUME[_add]
);
}
function getPoints(address _add) override public view returns (uint256 pointsFromSelf, uint256 pointsFromRef, uint256 pointsFromAdapter, uint256 pointsTotal) {
if (BLACKLISTED[_add]) return (0, 0, 0, 0);
uint256 userSelfVolMult = REFERRALS == address(0) ? 10000 : ISummitReferrals(REFERRALS).getSelfVolumeMultiplier(_add);
uint256 userRefVolMult = REFERRALS == address(0) ? 0 : ISummitReferrals(REFERRALS).getRefVolumeBonusMultiplier(_add);
pointsFromSelf = (SELF_VOLUME[_add] * userSelfVolMult * BASE_VOLUME_SCALER) / (10000 * 10000);
pointsFromRef = (REF_VOLUME[_add] * (REF_VOLUME_SCALER + userRefVolMult) * BASE_VOLUME_SCALER) / (10000 * 10000);
pointsFromAdapter = (ADAPTER_VOLUME[_add] * ADAPTER_VOLUME_SCALER * BASE_VOLUME_SCALER) / (10000 * 10000);
pointsTotal = pointsFromSelf + pointsFromRef + pointsFromAdapter;
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "./interface/ISummitRouter.sol";
import "./interface/IAdapter.sol";
import "./interface/IBlast.sol";
import "./interface/IERC20.sol";
import "./interface/IWETH.sol";
import "./lib/SafeERC20.sol";
import "./lib/Maintainable.sol";
import "./lib/SummitViewUtils.sol";
import "./lib/Recoverable.sol";
import "./interface/ISummitVolumeAdapter.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
contract SummitRouter is Maintainable, Recoverable, ISummitRouter {
using SafeERC20 for IERC20;
using OfferUtils for Offer;
using EnumerableSet for EnumerableSet.AddressSet;
address public immutable WNATIVE;
address public constant NATIVE = address(0);
string public constant NAME = "SummitRouter";
uint256 public constant FEE_DENOMINATOR = 1e4;
uint256 public MIN_FEE = 0;
address public FEE_CLAIMER;
address[] public TRUSTED_TOKENS;
mapping(address => uint256) public TOKEN_VOLUME_MULTIPLIERS; // (token amount * tokenVolumeMultiplier[token]) / 1e12
mapping(address => uint256) public TOKEN_VOLUME_BONUS;
address[] public ADAPTERS;
address public VOLUME_ADAPTER;
error AlreadyInitialized();
constructor(
address[] memory _adapters,
address[] memory _trustedTokens,
address _feeClaimer,
address _wrapped_native
) {
setAllowanceForWrapping(_wrapped_native);
setTrustedTokens(_trustedTokens);
setFeeClaimer(_feeClaimer);
setAdapters(_adapters);
WNATIVE = _wrapped_native;
}
bool public initialized = false;
address public governor;
function initialize(address _governor) public onlyMaintainer {
if (initialized) revert AlreadyInitialized();
initialized = true;
IBlast blast = IBlast(0x4300000000000000000000000000000000000002);
blast.configureClaimableGas();
blast.configureGovernor(_governor);
governor = _governor;
}
// -- SETTERS --
function setAllowanceForWrapping(address _wnative) public onlyMaintainer {
IERC20(_wnative).safeApprove(_wnative, type(uint256).max);
}
function setTrustedTokens(address[] memory _trustedTokens) override public onlyMaintainer {
emit UpdatedTrustedTokens(_trustedTokens);
TRUSTED_TOKENS = _trustedTokens;
}
function setTokenVolumeMultipliers(address[] memory _tokens, uint256[] memory _volumeMultipliers) public onlyMaintainer {
require(_tokens.length == _volumeMultipliers.length, "SummitRouter: Array length mismatch");
emit UpdatedTokenVolumeMultipliers(_tokens, _volumeMultipliers);
for (uint256 i = 0; i < _tokens.length; i++) {
TOKEN_VOLUME_MULTIPLIERS[_tokens[i]] = _volumeMultipliers[i];
}
}
function setTokenBonusMultipliers(address[] memory _tokens, uint256[] memory _multipliers) public onlyMaintainer {
require(_tokens.length == _multipliers.length, "SummitRouter: Array length mismatch");
emit UpdatedTokenBonusMultipliers(_tokens, _multipliers);
for (uint256 i = 0; i < _tokens.length; i++) {
TOKEN_VOLUME_BONUS[_tokens[i]] = _multipliers[i];
}
}
function setAdapters(address[] memory _adapters) override public onlyMaintainer {
emit UpdatedAdapters(_adapters);
ADAPTERS = _adapters;
}
function setVolumeAdapter(address _volumeAdapter) override public onlyMaintainer {
emit UpdatedVolumeAdapter(_volumeAdapter);
VOLUME_ADAPTER = _volumeAdapter;
}
function setMinFee(uint256 _fee) override external onlyMaintainer {
emit UpdatedMinFee(MIN_FEE, _fee);
MIN_FEE = _fee;
}
function setFeeClaimer(address _claimer) override public onlyMaintainer {
emit UpdatedFeeClaimer(FEE_CLAIMER, _claimer);
FEE_CLAIMER = _claimer;
}
// -- GENERAL --
function trustedTokensCount() override external view returns (uint256) {
return TRUSTED_TOKENS.length;
}
function adaptersCount() override external view returns (uint256) {
return ADAPTERS.length;
}
// Fallback
receive() external payable {}
// -- HELPERS --
function _applyFee(uint256 _amountIn, uint256 _fee) internal view returns (uint256) {
require(_fee >= MIN_FEE, "SummitRouter: Insufficient fee");
return (_amountIn * (FEE_DENOMINATOR - _fee)) / FEE_DENOMINATOR;
}
function _wrap(uint256 _amount) internal {
IWETH(WNATIVE).deposit{ value: _amount }();
}
function _unwrap(uint256 _amount) internal {
IWETH(WNATIVE).withdraw(_amount);
}
/**
* @notice Return tokens to user
* @dev Pass address(0) for NATIVE
* @param _token address
* @param _amount tokens to return
* @param _to address where funds should be sent to
*/
function _returnTokensTo(
address _token,
uint256 _amount,
address _to
) internal {
if (address(this) != _to) {
if (_token == NATIVE) {
payable(_to).transfer(_amount);
} else {
IERC20(_token).safeTransfer(_to, _amount);
}
}
}
function _transferFrom(address token, address _from, address _to, uint _amount) internal {
if (_from != address(this))
IERC20(token).safeTransferFrom(_from, _to, _amount);
else
IERC20(token).safeTransfer(_to, _amount);
}
// -- QUERIES --
/**
* Query single adapter
*/
function queryAdapter(
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
uint8 _index
) override external view returns (uint256) {
IAdapter _adapter = IAdapter(ADAPTERS[_index]);
uint256 amountOut = _adapter.query(_amountIn, _tokenIn, _tokenOut);
return amountOut;
}
/**
* Query specified adapters
*/
function queryNoSplit(
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
uint8[] calldata _options
) override public view returns (Query memory) {
Query memory bestQuery;
for (uint8 i; i < _options.length; i++) {
address _adapter = ADAPTERS[_options[i]];
uint256 amountOut = IAdapter(_adapter).query(_amountIn, _tokenIn, _tokenOut);
if (i == 0 || amountOut > bestQuery.amountOut) {
bestQuery = Query(_adapter, _tokenIn, _tokenOut, amountOut);
}
}
return bestQuery;
}
/**
* Query all adapters
*/
function queryNoSplit(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) override public view returns (Query memory) {
Query memory bestQuery;
for (uint8 i; i < ADAPTERS.length; i++) {
address _adapter = ADAPTERS[i];
uint256 amountOut = IAdapter(_adapter).query(_amountIn, _tokenIn, _tokenOut);
if (i == 0 || amountOut > bestQuery.amountOut) {
bestQuery = Query(_adapter, _tokenIn, _tokenOut, amountOut);
}
}
return bestQuery;
}
/**
* Return path with best returns between two tokens
* Takes gas-cost into account
*/
function findBestPathWithGas(
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
uint256 _maxSteps,
uint256 _gasPrice
) override external view returns (FormattedOffer memory) {
require(_maxSteps > 0 && _maxSteps < 5, "SummitRouter: Invalid max-steps");
Offer memory queries = OfferUtils.newOffer(_amountIn, _tokenIn);
uint256 gasPriceInExitTkn = _gasPrice > 0 ? getGasPriceInExitTkn(_gasPrice, _tokenOut) : 0;
queries = _findBestPath(_amountIn, _tokenIn, _tokenOut, _maxSteps, queries, gasPriceInExitTkn);
if (queries.adapters.length == 0) {
queries.amounts = "";
queries.path = "";
}
return queries.format();
}
// Find the market price between gas-asset(native) and token-out and express gas price in token-out
function getGasPriceInExitTkn(uint256 _gasPrice, address _tokenOut) internal view returns (uint256 price) {
// Avoid low-liquidity price appreciation (https://github.com/yieldsummit/summit-aggregator/issues/20)
FormattedOffer memory gasQuery = findBestPath(1e18, WNATIVE, _tokenOut, 2);
if (gasQuery.path.length != 0) {
// Leave result in nWei to preserve precision for assets with low decimal places
price = (gasQuery.amounts[gasQuery.amounts.length - 1] * _gasPrice) / 1e9;
}
}
/**
* Return path with best returns between two tokens
*/
function findBestPath(
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
uint256 _maxSteps
) override public view returns (FormattedOffer memory) {
require(_maxSteps > 0 && _maxSteps < 5, "SummitRouter: Invalid max-steps");
Offer memory queries = OfferUtils.newOffer(_amountIn, _tokenIn);
queries = _findBestPath(_amountIn, _tokenIn, _tokenOut, _maxSteps, queries, 0);
// If no paths are found return empty struct
if (queries.adapters.length == 0) {
queries.amounts = "";
queries.path = "";
}
return queries.format();
}
function _findBestPath(
uint256 _amountIn,
address _tokenIn,
address _tokenOut,
uint256 _maxSteps,
Offer memory _queries,
uint256 _tknOutPriceNwei
) internal view returns (Offer memory) {
Offer memory bestOption = _queries.clone();
uint256 bestAmountOut;
uint256 gasEstimate;
bool withGas = _tknOutPriceNwei != 0;
// First check if there is a path directly from tokenIn to tokenOut
Query memory queryDirect = queryNoSplit(_amountIn, _tokenIn, _tokenOut);
if (queryDirect.amountOut != 0) {
if (withGas) {
gasEstimate = IAdapter(queryDirect.adapter).swapGasEstimate();
}
bestOption.addToTail(queryDirect.amountOut, queryDirect.adapter, queryDirect.tokenOut, gasEstimate);
bestAmountOut = queryDirect.amountOut;
}
// Only check the rest if they would go beyond step limit (Need at least 2 more steps)
if (_maxSteps > 1 && _queries.adapters.length / 32 <= _maxSteps - 2) {
// Check for paths that pass through trusted tokens
for (uint256 i = 0; i < TRUSTED_TOKENS.length; i++) {
if (_tokenIn == TRUSTED_TOKENS[i]) {
continue;
}
// Loop through all adapters to find the best one for swapping tokenIn for one of the trusted tokens
Query memory bestSwap = queryNoSplit(_amountIn, _tokenIn, TRUSTED_TOKENS[i]);
if (bestSwap.amountOut == 0) {
continue;
}
// Explore options that connect the current path to the tokenOut
Offer memory newOffer = _queries.clone();
if (withGas) {
gasEstimate = IAdapter(bestSwap.adapter).swapGasEstimate();
}
newOffer.addToTail(bestSwap.amountOut, bestSwap.adapter, bestSwap.tokenOut, gasEstimate);
newOffer = _findBestPath(
bestSwap.amountOut,
TRUSTED_TOKENS[i],
_tokenOut,
_maxSteps,
newOffer,
_tknOutPriceNwei
); // Recursive step
address tokenOut = newOffer.getTokenOut();
uint256 amountOut = newOffer.getAmountOut();
// Check that the last token in the path is the tokenOut and update the new best option if neccesary
if (_tokenOut == tokenOut && amountOut > bestAmountOut) {
if (newOffer.gasEstimate > bestOption.gasEstimate) {
uint256 gasCostDiff = (_tknOutPriceNwei * (newOffer.gasEstimate - bestOption.gasEstimate)) /
1e9;
uint256 priceDiff = amountOut - bestAmountOut;
if (gasCostDiff > priceDiff) {
continue;
}
}
bestAmountOut = amountOut;
bestOption = newOffer;
}
}
}
return bestOption;
}
// -- VOLUME --
function getTokenBonus(address _token) override public view returns (uint256) {
if (_token == address(0)) return 0;
return TOKEN_VOLUME_BONUS[_token];
}
function _applyUserVolume(
address _from,
address[] memory _path,
uint256[] memory _amounts
) internal returns (uint256) {
if (VOLUME_ADAPTER == address(0)) return 0;
uint256 volume = 0;
uint256 bonus = 0;
for (uint256 i = 0; i < _path.length; i++) {
if (bonus == 0 && TOKEN_VOLUME_BONUS[_path[i]] != 0) {
bonus = TOKEN_VOLUME_BONUS[_path[i]];
}
if (volume == 0 && TOKEN_VOLUME_MULTIPLIERS[_path[i]] != 0) {
volume = TOKEN_VOLUME_MULTIPLIERS[_path[i]] * _amounts[i] / 1e12;
}
}
if (volume > 0 && VOLUME_ADAPTER != address(0)) {
ISummitVolumeAdapter(VOLUME_ADAPTER).addVolume(_from, (volume * (10000 + bonus)) / 10000);
}
return volume;
}
function _applyAdapterVolume(
address _adapter,
uint256 _volume
) internal {
if (_volume == 0 || VOLUME_ADAPTER == address(0)) return;
ISummitVolumeAdapter(VOLUME_ADAPTER).addAdapterVolume(_adapter, _volume);
}
// -- SWAPPERS --
function _swapNoSplit(
Trade calldata _trade,
address _from,
address _to,
uint256 _fee
) internal returns (uint256) {
uint256[] memory amounts = new uint256[](_trade.path.length);
if (_fee > 0 || MIN_FEE > 0) {
// Transfer fees to the claimer account and decrease initial amount
amounts[0] = _applyFee(_trade.amountIn, _fee);
_transferFrom(_trade.path[0], _from, address(this), _trade.amountIn - amounts[0]);
_transferFrom(_trade.path[0], address(this), FEE_CLAIMER, _trade.amountIn - amounts[0]);
} else {
amounts[0] = _trade.amountIn;
}
_transferFrom(_trade.path[0], _from, _trade.adapters[0], amounts[0]);
// Get amounts that will be swapped
for (uint256 i = 0; i < _trade.adapters.length; i++) {
amounts[i + 1] = IAdapter(_trade.adapters[i]).query(amounts[i], _trade.path[i], _trade.path[i + 1]);
}
// Add volume to user
uint256 volume = _applyUserVolume(msg.sender, _trade.path, amounts);
require(amounts[amounts.length - 1] >= _trade.amountOut, "SummitRouter: Insufficient output amount");
for (uint256 i = 0; i < _trade.adapters.length; i++) {
_applyAdapterVolume(_trade.adapters[i], volume);
// All adapters should transfer output token to the following target
// All targets are the adapters, expect for the last swap where tokens are sent out
address targetAddress = i < _trade.adapters.length - 1 ? _trade.adapters[i + 1] : _to;
IAdapter(_trade.adapters[i]).swap(
amounts[i],
amounts[i + 1],
_trade.path[i],
_trade.path[i + 1],
targetAddress
);
}
emit SummitSwap(_trade.path[0], _trade.path[_trade.path.length - 1], _trade.amountIn, amounts[amounts.length - 1]);
return amounts[amounts.length - 1];
}
function swapNoSplit(
Trade calldata _trade,
address _to,
uint256 _fee
) override public {
_swapNoSplit(_trade, msg.sender, _to, _fee);
}
function swapNoSplitFromNATIVE(
Trade calldata _trade,
address _to,
uint256 _fee
) override external payable {
require(_trade.path[0] == WNATIVE, "SummitRouter: Path needs to begin with WNATIVE");
_wrap(_trade.amountIn);
_swapNoSplit(_trade, address(this), _to, _fee);
}
function swapNoSplitToNATIVE(
Trade calldata _trade,
address _to,
uint256 _fee
) override public {
require(_trade.path[_trade.path.length - 1] == WNATIVE, "SummitRouter: Path needs to end with WNATIVE");
uint256 returnAmount = _swapNoSplit(_trade, msg.sender, address(this), _fee);
_unwrap(returnAmount);
_returnTokensTo(NATIVE, returnAmount, _to);
}
/**
* Swap token to token without the need to approve the first token
*/
function swapNoSplitWithPermit(
Trade calldata _trade,
address _to,
uint256 _fee,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) override external {
IERC20(_trade.path[0]).permit(msg.sender, address(this), _trade.amountIn, _deadline, _v, _r, _s);
swapNoSplit(_trade, _to, _fee);
}
/**
* Swap token to NATIVE without the need to approve the first token
*/
function swapNoSplitToNATIVEWithPermit(
Trade calldata _trade,
address _to,
uint256 _fee,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) override external {
IERC20(_trade.path[0]).permit(msg.sender, address(this), _trade.amountIn, _deadline, _v, _r, _s);
swapNoSplitToNATIVE(_trade, _to, _fee);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "./interface/ISummitVolumeAdapter.sol";
import "./interface/ISummitPoints.sol";
import "./interface/IAdapter.sol";
import "./interface/IBlast.sol";
import "./interface/IERC20.sol";
import "./interface/IWETH.sol";
import "./lib/SafeERC20.sol";
import "./lib/Maintainable.sol";
import "./lib/SummitViewUtils.sol";
import "./lib/Recoverable.sol";
import "./lib/SafeERC20.sol";
contract SummitVolumeAdapterV1 is Maintainable, Recoverable, ISummitVolumeAdapter {
address public ROUTER;
address public POINTS_CONTRACT;
error OnlyRouter();
error AlreadyInitialized();
bool public initialized = false;
address public governor;
function initialize(address _governor) public onlyMaintainer {
if (initialized) revert AlreadyInitialized();
initialized = true;
IBlast blast = IBlast(0x4300000000000000000000000000000000000002);
blast.configureClaimableGas();
blast.configureGovernor(_governor);
governor = _governor;
}
function setRouter(address _router) override public onlyMaintainer {
emit UpdatedRouter(_router);
ROUTER = _router;
}
function setPointsContract(address _pointsContract) override public onlyMaintainer {
emit UpdatedPointsContract(_pointsContract);
POINTS_CONTRACT = _pointsContract;
}
function addVolume(address _add, uint256 _volume) override public {
if (msg.sender != ROUTER) revert OnlyRouter();
if (POINTS_CONTRACT == address(0)) return;
ISummitPoints(POINTS_CONTRACT).addVolume(_add, _volume);
}
function addAdapterVolume(address _add, uint256 _volume) override public {
if (msg.sender != ROUTER) revert OnlyRouter();
if (POINTS_CONTRACT == address(0)) return;
ISummitPoints(POINTS_CONTRACT).addAdapterVolume(_add, _volume);
}
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "./SummitAdapter.sol";
abstract contract SummitWrapper is SummitAdapter {
constructor(string memory name, uint256 gasEstimate) SummitAdapter(name, gasEstimate) {}
function getTokensIn() external view virtual returns (address[] memory);
function getTokensOut() external view virtual returns (address[] memory);
function getWrappedToken() external view virtual returns (address);
}//
// __ ___ ___ __ _
// (_ | | |\/| |\/| | | (_ \ / /\ |_)
// __) |_| | | | | _|_ | __) \/\/ /--\ |
//
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;
import "../interface/IUniswapFactory.sol";
import "../interface/IUniswapPair.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
import "../SummitAdapter.sol";
contract DummyAdapter is SummitAdapter {
using SafeERC20 for IERC20;
IERC20 public A;
IERC20 public B;
uint256 AtoBPrice = 50;
constructor(
string memory _name,
uint256 _swapGasEstimate,
IERC20 tokenA,
IERC20 tokenB
) SummitAdapter(_name, _swapGasEstimate) {
A = tokenA;
B = tokenB;
}
function _getAmountOut(
uint256 _amountIn,
address _tokenIn
) internal view returns (uint256 amountOut) {
if (_tokenIn == address(A)) return _amountIn * AtoBPrice;
return _amountIn / AtoBPrice;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
return _getAmountOut(_amountIn, _tokenIn);
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address to
) internal override {
IERC20(_tokenOut).safeTransfer(to, _getAmountOut(_amountIn, _tokenIn));
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import "../SummitWrapper.sol";
interface ISomeExternalContract {
function getWhitelistedTokens() external view returns (address[] memory);
function getWrappedToken() external view returns (address);
function queryMint(address from, uint amount) external view returns (uint256);
function queryBurn(address to, uint amount) external view returns (uint256);
function mintWrappedToken(address from, uint amount) external;
function burnWrappedToken(address to, uint amount) external;
}
contract TestWrapper is SummitWrapper {
using SafeERC20 for IERC20;
address internal immutable someExternalContract;
mapping(address => bool) internal isWhitelisted;
address internal immutable wrappedToken;
address[] internal whitelistedTokens;
constructor(
string memory _name,
uint256 _gasEstimate,
address _someExternalContract
) SummitWrapper(_name, _gasEstimate) {
whitelistedTokens = ISomeExternalContract(_someExternalContract).getWhitelistedTokens();
wrappedToken = ISomeExternalContract(_someExternalContract).getWrappedToken();
someExternalContract = _someExternalContract;
}
function setWhitelistedTokens(address[] memory tokens) public onlyMaintainer {
for (uint i = 0; i < whitelistedTokens.length; i++) {
isWhitelisted[whitelistedTokens[i]] = false;
}
whitelistedTokens = tokens;
for (uint i = 0; i < tokens.length; i++) {
isWhitelisted[tokens[i]] = true;
}
}
function getTokensIn() override external view returns (address[] memory) {
return whitelistedTokens;
}
function getTokensOut() override external view returns (address[] memory) {
return whitelistedTokens;
}
function getWrappedToken() override external view returns (address) {
return wrappedToken;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) override internal view returns (uint256) {
if (_tokenIn == wrappedToken && isWhitelisted[_tokenOut]) {
return ISomeExternalContract(someExternalContract).queryBurn(_tokenOut, _amountIn);
} else if (_tokenOut == wrappedToken && isWhitelisted[_tokenIn]) {
return ISomeExternalContract(someExternalContract).queryMint(_tokenIn, _amountIn);
} else {
return 0;
}
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) override internal {
if (_tokenIn == wrappedToken && isWhitelisted[_tokenOut]) {
IERC20(_tokenOut).safeTransfer(someExternalContract, _amountIn);
ISomeExternalContract(someExternalContract).burnWrappedToken(_tokenOut, _amountIn);
} else if (_tokenOut == wrappedToken && isWhitelisted[_tokenIn]) {
IERC20(_tokenIn).safeTransfer(someExternalContract, _amountIn);
ISomeExternalContract(someExternalContract).mintWrappedToken(_tokenIn, _amountIn);
} else {
revert("Invalid token pair");
}
_returnTo(_tokenOut, _amountOut, _to);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import "../SummitWrapper.sol";
import "../interface/IGmxVault.sol";
import "../interface/IGlpManager.sol";
import "../interface/IGmxRewardRouter.sol";
import "../interface/IERC20.sol";
import "../lib/SafeERC20.sol";
contract GlpWrapper is SummitWrapper {
using SafeERC20 for IERC20;
uint256 public constant BASIS_POINTS_DIVISOR = 1e4;
uint256 public constant PRICE_PRECISION = 1e30;
address public immutable USDG;
address public immutable GLP;
address public immutable sGLP;
address public immutable vault;
address public immutable rewardRouter;
address public immutable glpManager;
address public immutable vaultUtils;
mapping(address => bool) internal isWhitelisted;
address[] internal whitelistedTokens;
constructor(
string memory _name,
uint256 _gasEstimate,
address _gmxRewardRouter,
address _glp,
address _sGlp
) SummitWrapper(_name, _gasEstimate) {
address gmxGLPManager = IGmxRewardRouter(_gmxRewardRouter).glpManager();
address gmxVault = IGlpManager(gmxGLPManager).vault();
USDG = IGmxVault(gmxVault).usdg();
vaultUtils = address(IGmxVault(gmxVault).vaultUtils());
rewardRouter = _gmxRewardRouter;
vault = gmxVault;
glpManager = gmxGLPManager;
GLP = _glp;
sGLP = _sGlp;
}
function setWhitelistedTokens(address[] memory tokens) public onlyMaintainer {
for (uint256 i = 0; i < whitelistedTokens.length; i++) {
isWhitelisted[whitelistedTokens[i]] = false;
}
whitelistedTokens = tokens;
for (uint256 i = 0; i < tokens.length; i++) {
isWhitelisted[tokens[i]] = true;
}
}
function getTokensIn() external view override returns (address[] memory) {
return whitelistedTokens;
}
function getTokensOut() external view override returns (address[] memory) {
return whitelistedTokens;
}
function getWrappedToken() external view override returns (address) {
return sGLP;
}
function _query(
uint256 _amountIn,
address _tokenIn,
address _tokenOut
) internal view override returns (uint256 amountOut) {
return (_tokenOut == sGLP) ? _quoteBuyGLP(_tokenIn, _amountIn) : _quoteSellGLP(_tokenOut, _amountIn);
}
function _quoteBuyGLP(address _tokenIn, uint256 _amountIn) internal view returns (uint256 amountOut) {
uint256 aumInUsdg = IGlpManager(glpManager).getAumInUsdg(true);
uint256 glpSupply = IERC20(GLP).totalSupply();
uint256 price = IGmxVault(vault).getMinPrice(_tokenIn);
uint256 usdgAmount = _calculateBuyUsdg(_amountIn, price, _tokenIn);
amountOut = aumInUsdg == 0 ? usdgAmount : (usdgAmount * glpSupply) / aumInUsdg;
}
function _calculateBuyUsdg(
uint256 _amountIn,
uint256 _price,
address _tokenIn
) internal view returns (uint256 amountOut) {
amountOut = (_amountIn * _price) / PRICE_PRECISION;
amountOut = IGmxVault(vault).adjustForDecimals(amountOut, _tokenIn, USDG);
uint256 feeBasisPoints = IGmxVaultUtils(vaultUtils).getBuyUsdgFeeBasisPoints(_tokenIn, amountOut);
uint256 amountAfterFees = (_amountIn * (BASIS_POINTS_DIVISOR - feeBasisPoints)) / BASIS_POINTS_DIVISOR;
amountOut = (amountAfterFees * _price) / PRICE_PRECISION;
amountOut = IGmxVault(vault).adjustForDecimals(amountOut, _tokenIn, USDG);
}
function _quoteSellGLP(address _tokenOut, uint256 _amountIn) internal view returns (uint256 amountOut) {
uint256 aumInUsdg = IGlpManager(glpManager).getAumInUsdg(false);
uint256 glpSupply = IERC20(GLP).totalSupply();
uint256 usdgAmount = (_amountIn * aumInUsdg) / glpSupply;
uint256 redemptionAmount = IGmxVault(vault).getRedemptionAmount(_tokenOut, usdgAmount);
uint256 feeBasisPoints = calculateSellUsdgFeeBasisPoints(_tokenOut, usdgAmount);
amountOut = (redemptionAmount * (BASIS_POINTS_DIVISOR - feeBasisPoints)) / BASIS_POINTS_DIVISOR;
}
function calculateSellUsdgFeeBasisPoints(address _token, uint256 _usdgDelta) internal view returns (uint256) {
uint feeBasisPoints = IGmxVault(vault).mintBurnFeeBasisPoints();
uint taxBasisPoints = IGmxVault(vault).taxBasisPoints();
if (!IGmxVault(vault).hasDynamicFees()) {
return feeBasisPoints;
}
uint256 initialAmount = IGmxVault(vault).usdgAmounts(_token) - _usdgDelta;
uint256 nextAmount = _usdgDelta > initialAmount ? 0 : initialAmount - _usdgDelta;
uint256 targetAmount = IGmxVault(vault).getTargetUsdgAmount(_token);
if (targetAmount == 0) {
return feeBasisPoints;
}
uint256 initialDiff = initialAmount > targetAmount
? initialAmount - targetAmount
: targetAmount - initialAmount;
uint256 nextDiff = nextAmount > targetAmount ? nextAmount - targetAmount : targetAmount - nextAmount;
if (nextDiff < initialDiff) {
uint256 rebateBps = (taxBasisPoints * initialDiff) / targetAmount;
return rebateBps > feeBasisPoints ? 0 : feeBasisPoints - rebateBps;
}
uint256 averageDiff = (initialDiff + nextDiff) / 2;
if (averageDiff > targetAmount) {
averageDiff = targetAmount;
}
uint256 taxBps = (taxBasisPoints * averageDiff) / targetAmount;
return feeBasisPoints + taxBps;
}
function _swap(
uint256 _amountIn,
uint256 _amountOut,
address _tokenIn,
address _tokenOut,
address _to
) internal override {}
function swap(
uint256 _amountIn,
uint256 _amountOut,
address _fromToken,
address _toToken,
address _to
) external override {
uint256 toBalanceBefore = IERC20(_toToken).balanceOf(_to);
if (_toToken == sGLP) {
IERC20(_fromToken).approve(glpManager, _amountIn);
uint256 amount = IGmxRewardRouter(rewardRouter).mintAndStakeGlp(_fromToken, _amountIn, 0, _amountOut);
_returnTo(sGLP, amount, _to);
} else {
IGmxRewardRouter(rewardRouter).unstakeAndRedeemGlp(_toToken, _amountIn, _amountOut, _to);
}
uint256 diff = IERC20(_toToken).balanceOf(_to) - toBalanceBefore;
require(diff >= _amountOut, "Insufficient amount-out");
emit SummitAdapterSwap(_fromToken, _toToken, _amountIn, _amountOut);
}
}{
"optimizer": {
"enabled": true,
"runs": 999
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlreadyReferredByUser","type":"error"},{"inputs":[],"name":"AlreadySetCode","type":"error"},{"inputs":[],"name":"CodeNotAvailable","type":"error"},{"inputs":[],"name":"InvalidCode","type":"error"},{"inputs":[],"name":"InvalidLevel","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"MissingReferral","type":"error"},{"inputs":[],"name":"MustBeAtLeastBronze","type":"error"},{"inputs":[],"name":"ReciprocalReferral","type":"error"},{"inputs":[],"name":"SelfReferral","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"uint8","name":"_boostLevel","type":"uint8"}],"name":"BoostedReferrer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"referrer","type":"address[]"},{"indexed":false,"internalType":"uint8[]","name":"_boostLevel","type":"uint8[]"}],"name":"BoostedReferrers","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"_refPointsReq","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"_selfPointsReq","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"_refsReq","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"_multRew","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"_hasReferrerBonusMult","type":"uint256"}],"name":"UpdatedLevelData","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_pointsContract","type":"address"}],"name":"UpdatedPointsContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_caller","type":"address"},{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"string","name":"_code","type":"string"}],"name":"UpdatedReferralCode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_add","type":"address"},{"indexed":true,"internalType":"address","name":"_referrer","type":"address"}],"name":"UpdatedReferrer","type":"event"},{"inputs":[],"name":"BONUS_FOR_BEING_REFERRED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"LEVEL_MULT_REWARD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"LEVEL_REFS_REQ","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"LEVEL_REF_VOLUME_REQ","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"LEVEL_SELF_VOLUME_REQ","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINTAINER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"REFERRER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"REF_BOOST_LEVEL","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"REF_CODE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"REF_CODE_INV","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"REF_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUMMIT_POINTS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addedMaintainer","type":"address"}],"name":"addMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"uint8","name":"_boostLevel","type":"uint8"}],"name":"boostReferrer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_referrers","type":"address[]"},{"internalType":"uint8[]","name":"_levels","type":"uint8[]"}],"name":"boostReferrers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_level","type":"uint8"}],"name":"getLevelRequirements","outputs":[{"internalType":"uint256","name":"selfVolume","type":"uint256"},{"internalType":"uint256","name":"refVolume","type":"uint256"},{"internalType":"uint256","name":"refsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_add","type":"address"}],"name":"getRefVolumeBonusMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_add","type":"address"}],"name":"getReferrer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_add","type":"address"}],"name":"getReferrerCode","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_add","type":"address"}],"name":"getReferrerLevel","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_add","type":"address"}],"name":"getReferrerLevelWithoutBoost","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_add","type":"address"}],"name":"getRefsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_add","type":"address"}],"name":"getSelfVolumeMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_add","type":"address"}],"name":"getUserNextLevelRequirements","outputs":[{"internalType":"uint256","name":"selfVolume","type":"uint256"},{"internalType":"uint256","name":"refVolume","type":"uint256"},{"internalType":"uint256","name":"refsCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_governor","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"levelCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_add","type":"address"},{"internalType":"string","name":"_code","type":"string"}],"name":"maintainerSetReferralCode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"removedMaintainer","type":"address"}],"name":"removeMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_refVolumeReq","type":"uint256[]"},{"internalType":"uint256[]","name":"_selfVolumeReq","type":"uint256[]"},{"internalType":"uint256[]","name":"_refsReq","type":"uint256[]"},{"internalType":"uint256[]","name":"_multReward","type":"uint256[]"},{"internalType":"uint256","name":"_hasReferrerBonusMult","type":"uint256"}],"name":"setLevelData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pointsContract","type":"address"}],"name":"setPointsContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_code","type":"string"}],"name":"setReferralCode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"string","name":"_code","type":"string"}],"name":"setReferrer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6080604052600660025560c8600755600d805460ff191690553480156200002557600080fd5b5062000033600033620002ad565b6200005f7f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab9533620002ad565b60006040518060c00160405280600081526020016000815260200169021e19e0c9bab2400000815260200169054b40b1f852bda00000815260200169152d02c7e14af6800000815260200169d3c21bcecceda1000000815250905060006040518060c001604052806000815260200168056bc75e2d631000008152602001683635c9adc5dea000008152602001686c6b935b8bbd400000815260200169010f0cf064dd59200000815260200169054b40b1f852bda00000815250905060006040518060c0016040528060008152602001600081526020016003815260200160058152602001600a81526020016019815250905060006040518060c001604052806000815260200160c8815260200161019081526020016101f481526020016102bc81526020016105dc815250905060005b600254811015620002a257848160068110620001bc57634e487b7160e01b600052603260045260246000fd5b60200201516003600083815260200190815260200160002081905550838160068110620001f957634e487b7160e01b600052603260045260246000fd5b602002015160046000838152602001908152602001600020819055508281600681106200023657634e487b7160e01b600052603260045260246000fd5b602002015160056000838152602001908152602001600020819055508181600681106200027357634e487b7160e01b600052603260045260246000fd5b60209081029190910151600083815260069092526040909120558062000299816200035d565b91505062000190565b505050505062000385565b620002b98282620002bd565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620002b9576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620003193390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006000198214156200037e57634e487b7160e01b81526011600452602481fd5b5060010190565b612a4f80620003956000396000f3fe608060405234801561001057600080fd5b50600436106102e95760003560e01c806391d1485411610191578063c4d66de8116100e3578063e0f442d511610097578063fa98b69d11610071578063fa98b69d1461072f578063fb4e6c2d1461074f578063fd0dfb851461076257600080fd5b8063e0f442d5146106e2578063f2fde38b146106f5578063f87422541461070857600080fd5b8063d547741f116100c8578063d547741f146106a9578063d8baf7cf146106bc578063de2ad91a146106cf57600080fd5b8063c4d66de81461066d578063ce0b66391461068057600080fd5b8063a4b0df2511610145578063b8ef9fb31161011f578063b8ef9fb314610611578063ba32aa151461063a578063bc826e641461064d57600080fd5b8063a4b0df25146105cb578063a8654bcb146105de578063affb41a0146105f157600080fd5b8063982b6d4511610176578063982b6d451461056e5780639e8d7cd4146105a3578063a217fddf146105c357600080fd5b806391d148541461052457806395754abb1461055b57600080fd5b80634c10fb251161024a578063651a2b4c116101fe5780637c4e94b5116101d85780637c4e94b5146104de57806386ec3e3d146104fe5780638bb9c5bf1461051157600080fd5b8063651a2b4c146104af5780636b453c1f146104b857806373930f04146104cb57600080fd5b806359ee3c5b1161022f57806359ee3c5b146104485780635a3553c9146104685780635cefd2c61461049c57600080fd5b80634c10fb2514610407578063570f61eb1461041a57600080fd5b8063248a9ca3116102a157806336568abe1161028657806336568abe146103b55780633fe9bba8146103c85780634a9fefc7146103db57600080fd5b8063248a9ca31461037d5780632f2ff15d146103a057600080fd5b8063080472d2116102d2578063080472d21461032d5780630c340a2414610358578063158ef93e1461037057600080fd5b806301e6896b146102ee57806301ffc9a71461030a575b600080fd5b6102f760075481565b6040519081526020015b60405180910390f35b61031d610318366004612528565b610775565b6040519015158152602001610301565b600154610340906001600160a01b031681565b6040516001600160a01b039091168152602001610301565b600d546103409061010090046001600160a01b031681565b600d5461031d9060ff1681565b6102f761038b3660046124ee565b60009081526020819052604090206001015490565b6103b36103ae366004612506565b61080e565b005b6103b36103c3366004612506565b610838565b6103b36103d636600461243e565b6108c9565b6103406103e93660046122ef565b6001600160a01b039081166000908152600860205260409020541690565b6103b3610415366004612355565b610b1a565b61042d6104283660046125d0565b610c09565b60408051938452602084019290925290820152606001610301565b61045b6104563660046122ef565b610c7b565b6040516103019190612835565b610340610476366004612568565b8051602081830181018051600b825292820191909301209152546001600160a01b031681565b6103b36104aa366004612387565b610d15565b6102f760025481565b6103b36104c63660046122ef565b610f43565b6102f76104d93660046122ef565b610f70565b6102f76104ec3660046124ee565b60036020526000908152604090205481565b6103b361050c366004612568565b610fa8565b6103b361051f3660046124ee565b6111a6565b61031d610532366004612506565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6103b36105693660046122ef565b6111b0565b61059161057c3660046122ef565b600a6020526000908152604090205460ff1681565b60405160ff9091168152602001610301565b6102f76105b13660046124ee565b60046020526000908152604090205481565b6102f7600081565b61042d6105d93660046122ef565b611295565b6102f76105ec3660046122ef565b6112fb565b6102f76105ff3660046124ee565b60056020526000908152604090205481565b61034061061f3660046122ef565b6008602052600090815260409020546001600160a01b031681565b6103b3610648366004612309565b611323565b6102f761065b3660046122ef565b60096020526000908152604090205481565b6103b361067b3660046122ef565b6114f0565b6102f761068e3660046122ef565b6001600160a01b031660009081526009602052604090205490565b6103b36106b7366004612506565b6116fe565b6103b36106ca3660046122ef565b611723565b6105916106dd3660046122ef565b61174d565b61045b6106f03660046122ef565b6117d7565b6103b36107033660046122ef565b611892565b6102f77f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab9581565b6102f761073d3660046124ee565b60066020526000908152604090205481565b61059161075d3660046122ef565b6118a8565b6103b3610770366004612309565b611a39565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061080857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60008281526020819052604090206001015461082981611d11565b6108338383611d1b565b505050565b6001600160a01b03811633146108bb5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6108c58282611db9565b5050565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff166109585760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b8351855114158061096b57508251855114155b8061097857508151855114155b156109af576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845160005b81811015610ac7578681815181106109dc57634e487b7160e01b600052603260045260246000fd5b60200260200101516003600083815260200190815260200160002081905550858181518110610a1b57634e487b7160e01b600052603260045260246000fd5b60200260200101516004600083815260200190815260200160002081905550848181518110610a5a57634e487b7160e01b600052603260045260246000fd5b60200260200101516005600083815260200190815260200160002081905550838181518110610a9957634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516000838152600690925260409091205580610abf816129b2565b9150506109b4565b50600281905560078290556040517f562c204f2c2ef9fa88aa881cd4d49bc65849451a4bdb97fad62dc3a5eae6041390610b0a90889088908890889088906127d5565b60405180910390a1505050505050565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff16610ba95760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b6001600160a01b0382166000818152600a6020908152604091829020805460ff191660ff861690811790915591519182527fc4f4125174e3f54bd4ffb0f92384ddca0b2dc931f194e9f5efb1a1b88443fb32910160405180910390a25050565b60008060006002548460ff1610610c4c576040517fd1459f7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505060ff16600090815260046020908152604080832054600383528184205460059093529220549192909190565b600c6020526000908152604090208054610c9490612977565b80601f0160208091040260200160405190810160405280929190818152602001828054610cc090612977565b8015610d0d5780601f10610ce257610100808354040283529160200191610d0d565b820191906000526020600020905b815481529060010190602001808311610cf057829003601f168201915b505050505081565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff16610da45760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b8051825114610ddf576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610f0557818181518110610e0b57634e487b7160e01b600052603260045260246000fd5b602002602001015160ff16600a6000858481518110610e3a57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1614610ef357818181518110610e8657634e487b7160e01b600052603260045260246000fd5b6020026020010151600a6000858481518110610eb257634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908360ff1602179055505b80610efd816129b2565b915050610de2565b507fa8ebc437633f921c0b85258fb33b74715331194b7fdc1627091b38ce0ea7afd48282604051610f3792919061275c565b60405180910390a15050565b610f6d7f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab958261080e565b50565b6001600160a01b03818116600090815260086020526040812054909116610f98576000610f9c565b6007545b610808906127106128bd565b600381511080610fb95750600f8151115b15610ff0576040517f6606a46200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600c60205260409020805461100a90612977565b159050611043576040517fad51e20300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61104c3361174d565b60ff1661106c576040516338b729c360e11b815260040160405180910390fd5b60006001600160a01b0316600b826040516110879190612624565b908152604051908190036020019020546001600160a01b0316146110be5760405163096a1aab60e21b815260040160405180910390fd5b336000908152600c60205260408082209051600b916110dc91612640565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039490941693909317909255336000908152600c8252919091208251611128928401906120eb565b5033600b8260405161113a9190612624565b90815260405190819003602001812080546001600160a01b03939093166001600160a01b031990931692909217909155339081907f627a1b03408ad803620768c059b68f695d3740108ac22fd6cdab3c887b162cbe9061119b908590612835565b60405180910390a350565b610f6d8133610838565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff1661123f5760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b6040516001600160a01b038216907fc44f7b4fe9d29c078d207864fd556e8b68e1759e3ac4ee9cece99d2ec03c27c690600090a2600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000806000806112a4856118a8565b6112af9060016128d5565b9050600060016002546112c29190612919565b8260ff1610156112d257816112e1565b60016002546112e19190612919565b90506112ec81610c09565b94509450945050509193909250565b60006006600061130a8461174d565b60ff168152602001908152602001600020549050919050565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff166113b25760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b60006001600160a01b0316600b826040516113cd9190612624565b908152604051908190036020019020546001600160a01b0316146114045760405163096a1aab60e21b815260040160405180910390fd5b6001600160a01b0382166000908152600c60205260408082209051600b9161142b91612640565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039485161790559184166000908152600c8252919091208251611474928401906120eb565b5081600b826040516114869190612624565b90815260405190819003602001812080546001600160a01b039384166001600160a01b03199091161790559083169033907f627a1b03408ad803620768c059b68f695d3740108ac22fd6cdab3c887b162cbe906114e4908590612835565b60405180910390a35050565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff1661157f5760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b600d5460ff16156115bc576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d805460ff19166001179055604080517f4e606c470000000000000000000000000000000000000000000000000000000081529051734300000000000000000000000000000000000002918291634e606c479160048082019260009290919082900301818387803b15801561163157600080fd5b505af1158015611645573d6000803e3d6000fd5b50506040517feb8646980000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416925063eb8646989150602401600060405180830381600087803b1580156116a557600080fd5b505af11580156116b9573d6000803e3d6000fd5b5050600d80546001600160a01b03909516610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff90951694909417909355505050565b60008281526020819052604090206001015461171981611d11565b6108338383611db9565b610f6d7f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab95826116fe565b6001600160a01b0381166000908152600a602052604081205460ff16156117ce57600160025461177d9190612919565b6001600160a01b0383166000908152600a602052604090205460ff16116117bf576001600160a01b0382166000908152600a602052604090205460ff16610808565b60016002546108089190612919565b610808826118a8565b6001600160a01b038082166000908152600860209081526040808320549093168252600c90522080546060919061180d90612977565b80601f016020809104026020016040519081016040528092919081815260200182805461183990612977565b80156118865780601f1061185b57610100808354040283529160200191611886565b820191906000526020600020905b81548152906001019060200180831161186957829003601f168201915b50505050509050919050565b61189d60008261080e565b610f6d600033610838565b6001546000906001600160a01b03166118c357506000919050565b6001546040517f8ba17f860000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526000928392911690638ba17f869060240160606040518083038186803b15801561192557600080fd5b505afa158015611939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195d91906125a3565b509150915060005b6002548160ff161015611a2d57600460006119818360016128d5565b60ff168152602001908152602001600020548310156119a257949350505050565b600360006119b18360016128d5565b60ff168152602001908152602001600020548210156119d257949350505050565b600560006119e18360016128d5565b60ff16815260208082019290925260409081016000908120546001600160a01b0389168252600990935220541015611a1b57949350505050565b80611a25816129cd565b915050611965565b50506002549392505050565b60006001600160a01b03831615611a505782611a7a565b600b82604051611a609190612624565b908152604051908190036020019020546001600160a01b03165b90506001600160a01b038116611abc576040517fcd2d66aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116331415611aff576040517f55e8f70e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546001600160a01b0382811691161415611b54576040517ffe1ffa9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381811660009081526008602052604090205416331415611b8f5760405163b6ea0b0160e01b815260040160405180910390fd5b6001600160a01b03818116600090815260086020526040808220548316825290205416331415611bd25760405163b6ea0b0160e01b815260040160405180910390fd5b611bdb8161174d565b60ff16611bfb576040516338b729c360e11b815260040160405180910390fd5b336000908152600860205260409020546001600160a01b031615801590611c485750336000908152600860209081526040808320546001600160a01b031683526009909152902054600111155b15611c8957336000908152600860209081526040808320546001600160a01b0316835260099091528120805460019290611c83908490612919565b90915550505b33600090815260086020908152604080832080546001600160a01b0319166001600160a01b038616908117909155835260099091528120805460019290611cd19084906128bd565b90915550506040516001600160a01b0382169033907f82ca166ebb8d22637409e8fcca994e7e1b757a1e28f0ee91f4defe3cff1e919390600090a3505050565b610f6d8133611e38565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166108c5576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055611d753390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16156108c5576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166108c557611e6981611eab565b611e74836020611ebd565b604051602001611e859291906126db565b60408051601f198184030181529082905262461bcd60e51b82526108b291600401612835565b60606108086001600160a01b03831660145b60606000611ecc8360026128fa565b611ed79060026128bd565b67ffffffffffffffff811115611efd57634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015611f27576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611f6c57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611fc557634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053506000611fe98460026128fa565b611ff49060016128bd565b90505b6001811115612095577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061204357634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061206757634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c9361208e81612960565b9050611ff7565b5083156120e45760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108b2565b9392505050565b8280546120f790612977565b90600052602060002090601f016020900481019282612119576000855561215f565b82601f1061213257805160ff191683800117855561215f565b8280016001018555821561215f579182015b8281111561215f578251825591602001919060010190612144565b5061216b92915061216f565b5090565b5b8082111561216b5760008155600101612170565b80356001600160a01b038116811461219b57600080fd5b919050565b600082601f8301126121b0578081fd5b813560206121c56121c083612899565b612868565b80838252828201915082860187848660051b89010111156121e4578586fd5b855b85811015612202578135845292840192908401906001016121e6565b5090979650505050505050565b600082601f83011261221f578081fd5b8135602061222f6121c083612899565b80838252828201915082860187848660051b890101111561224e578586fd5b855b8581101561220257612261826122de565b84529284019290840190600101612250565b600082601f830112612283578081fd5b813567ffffffffffffffff81111561229d5761229d612a03565b6122b0601f8201601f1916602001612868565b8181528460208386010111156122c4578283fd5b816020850160208301379081016020019190915292915050565b803560ff8116811461219b57600080fd5b600060208284031215612300578081fd5b6120e482612184565b6000806040838503121561231b578081fd5b61232483612184565b9150602083013567ffffffffffffffff81111561233f578182fd5b61234b85828601612273565b9150509250929050565b60008060408385031215612367578182fd5b61237083612184565b915061237e602084016122de565b90509250929050565b60008060408385031215612399578182fd5b823567ffffffffffffffff808211156123b0578384fd5b818501915085601f8301126123c3578384fd5b813560206123d36121c083612899565b8083825282820191508286018a848660051b89010111156123f2578889fd5b8896505b8487101561241b5761240781612184565b8352600196909601959183019183016123f6565b5096505086013592505080821115612431578283fd5b5061234b8582860161220f565b600080600080600060a08688031215612455578081fd5b853567ffffffffffffffff8082111561246c578283fd5b61247889838a016121a0565b9650602088013591508082111561248d578283fd5b61249989838a016121a0565b955060408801359150808211156124ae578283fd5b6124ba89838a016121a0565b945060608801359150808211156124cf578283fd5b506124dc888289016121a0565b95989497509295608001359392505050565b6000602082840312156124ff578081fd5b5035919050565b60008060408385031215612518578182fd5b8235915061237e60208401612184565b600060208284031215612539578081fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146120e4578182fd5b600060208284031215612579578081fd5b813567ffffffffffffffff81111561258f578182fd5b61259b84828501612273565b949350505050565b6000806000606084860312156125b7578081fd5b8351925060208401519150604084015190509250925092565b6000602082840312156125e1578081fd5b6120e4826122de565b6000815180845260208085019450808401835b83811015612619578151875295820195908201906001016125fd565b509495945050505050565b60008251612636818460208701612930565b9190910192915050565b600080835482600182811c91508083168061265c57607f831692505b602080841082141561267c57634e487b7160e01b87526022600452602487fd5b81801561269057600181146126a1576126cd565b60ff198616895284890196506126cd565b60008a815260209020885b868110156126c55781548b8201529085019083016126ac565b505084890196505b509498975050505050505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612713816017850160208801612930565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612750816028840160208801612930565b01602801949350505050565b604080825283519082018190526000906020906060840190828701845b8281101561279e5781516001600160a01b031684529284019290840190600101612779565b50505083810382850152845180825285830191830190845b8181101561220257835160ff16835292840192918401916001016127b6565b60a0815260006127e860a08301886125ea565b82810360208401526127fa81886125ea565b9050828103604084015261280e81876125ea565b9050828103606084015261282281866125ea565b9150508260808301529695505050505050565b6020815260008251806020840152612854816040850160208701612930565b601f01601f19169190910160400192915050565b604051601f8201601f1916810167ffffffffffffffff8111828210171561289157612891612a03565b604052919050565b600067ffffffffffffffff8211156128b3576128b3612a03565b5060051b60200190565b600082198211156128d0576128d06129ed565b500190565b600060ff821660ff84168060ff038211156128f2576128f26129ed565b019392505050565b6000816000190483118215151615612914576129146129ed565b500290565b60008282101561292b5761292b6129ed565b500390565b60005b8381101561294b578181015183820152602001612933565b8381111561295a576000848401525b50505050565b60008161296f5761296f6129ed565b506000190190565b600181811c9082168061298b57607f821691505b602082108114156129ac57634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156129c6576129c66129ed565b5060010190565b600060ff821660ff8114156129e4576129e46129ed565b60010192915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fdfea264697066735822122081cb55390721778e5ebde06ffdba4100e63be4df1d04c411eb635601e1b13d2164736f6c63430008040033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102e95760003560e01c806391d1485411610191578063c4d66de8116100e3578063e0f442d511610097578063fa98b69d11610071578063fa98b69d1461072f578063fb4e6c2d1461074f578063fd0dfb851461076257600080fd5b8063e0f442d5146106e2578063f2fde38b146106f5578063f87422541461070857600080fd5b8063d547741f116100c8578063d547741f146106a9578063d8baf7cf146106bc578063de2ad91a146106cf57600080fd5b8063c4d66de81461066d578063ce0b66391461068057600080fd5b8063a4b0df2511610145578063b8ef9fb31161011f578063b8ef9fb314610611578063ba32aa151461063a578063bc826e641461064d57600080fd5b8063a4b0df25146105cb578063a8654bcb146105de578063affb41a0146105f157600080fd5b8063982b6d4511610176578063982b6d451461056e5780639e8d7cd4146105a3578063a217fddf146105c357600080fd5b806391d148541461052457806395754abb1461055b57600080fd5b80634c10fb251161024a578063651a2b4c116101fe5780637c4e94b5116101d85780637c4e94b5146104de57806386ec3e3d146104fe5780638bb9c5bf1461051157600080fd5b8063651a2b4c146104af5780636b453c1f146104b857806373930f04146104cb57600080fd5b806359ee3c5b1161022f57806359ee3c5b146104485780635a3553c9146104685780635cefd2c61461049c57600080fd5b80634c10fb2514610407578063570f61eb1461041a57600080fd5b8063248a9ca3116102a157806336568abe1161028657806336568abe146103b55780633fe9bba8146103c85780634a9fefc7146103db57600080fd5b8063248a9ca31461037d5780632f2ff15d146103a057600080fd5b8063080472d2116102d2578063080472d21461032d5780630c340a2414610358578063158ef93e1461037057600080fd5b806301e6896b146102ee57806301ffc9a71461030a575b600080fd5b6102f760075481565b6040519081526020015b60405180910390f35b61031d610318366004612528565b610775565b6040519015158152602001610301565b600154610340906001600160a01b031681565b6040516001600160a01b039091168152602001610301565b600d546103409061010090046001600160a01b031681565b600d5461031d9060ff1681565b6102f761038b3660046124ee565b60009081526020819052604090206001015490565b6103b36103ae366004612506565b61080e565b005b6103b36103c3366004612506565b610838565b6103b36103d636600461243e565b6108c9565b6103406103e93660046122ef565b6001600160a01b039081166000908152600860205260409020541690565b6103b3610415366004612355565b610b1a565b61042d6104283660046125d0565b610c09565b60408051938452602084019290925290820152606001610301565b61045b6104563660046122ef565b610c7b565b6040516103019190612835565b610340610476366004612568565b8051602081830181018051600b825292820191909301209152546001600160a01b031681565b6103b36104aa366004612387565b610d15565b6102f760025481565b6103b36104c63660046122ef565b610f43565b6102f76104d93660046122ef565b610f70565b6102f76104ec3660046124ee565b60036020526000908152604090205481565b6103b361050c366004612568565b610fa8565b6103b361051f3660046124ee565b6111a6565b61031d610532366004612506565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6103b36105693660046122ef565b6111b0565b61059161057c3660046122ef565b600a6020526000908152604090205460ff1681565b60405160ff9091168152602001610301565b6102f76105b13660046124ee565b60046020526000908152604090205481565b6102f7600081565b61042d6105d93660046122ef565b611295565b6102f76105ec3660046122ef565b6112fb565b6102f76105ff3660046124ee565b60056020526000908152604090205481565b61034061061f3660046122ef565b6008602052600090815260409020546001600160a01b031681565b6103b3610648366004612309565b611323565b6102f761065b3660046122ef565b60096020526000908152604090205481565b6103b361067b3660046122ef565b6114f0565b6102f761068e3660046122ef565b6001600160a01b031660009081526009602052604090205490565b6103b36106b7366004612506565b6116fe565b6103b36106ca3660046122ef565b611723565b6105916106dd3660046122ef565b61174d565b61045b6106f03660046122ef565b6117d7565b6103b36107033660046122ef565b611892565b6102f77f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab9581565b6102f761073d3660046124ee565b60066020526000908152604090205481565b61059161075d3660046122ef565b6118a8565b6103b3610770366004612309565b611a39565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061080857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60008281526020819052604090206001015461082981611d11565b6108338383611d1b565b505050565b6001600160a01b03811633146108bb5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6108c58282611db9565b5050565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff166109585760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b8351855114158061096b57508251855114155b8061097857508151855114155b156109af576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845160005b81811015610ac7578681815181106109dc57634e487b7160e01b600052603260045260246000fd5b60200260200101516003600083815260200190815260200160002081905550858181518110610a1b57634e487b7160e01b600052603260045260246000fd5b60200260200101516004600083815260200190815260200160002081905550848181518110610a5a57634e487b7160e01b600052603260045260246000fd5b60200260200101516005600083815260200190815260200160002081905550838181518110610a9957634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516000838152600690925260409091205580610abf816129b2565b9150506109b4565b50600281905560078290556040517f562c204f2c2ef9fa88aa881cd4d49bc65849451a4bdb97fad62dc3a5eae6041390610b0a90889088908890889088906127d5565b60405180910390a1505050505050565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff16610ba95760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b6001600160a01b0382166000818152600a6020908152604091829020805460ff191660ff861690811790915591519182527fc4f4125174e3f54bd4ffb0f92384ddca0b2dc931f194e9f5efb1a1b88443fb32910160405180910390a25050565b60008060006002548460ff1610610c4c576040517fd1459f7900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505060ff16600090815260046020908152604080832054600383528184205460059093529220549192909190565b600c6020526000908152604090208054610c9490612977565b80601f0160208091040260200160405190810160405280929190818152602001828054610cc090612977565b8015610d0d5780601f10610ce257610100808354040283529160200191610d0d565b820191906000526020600020905b815481529060010190602001808311610cf057829003601f168201915b505050505081565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff16610da45760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b8051825114610ddf576040517fff633a3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610f0557818181518110610e0b57634e487b7160e01b600052603260045260246000fd5b602002602001015160ff16600a6000858481518110610e3a57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1614610ef357818181518110610e8657634e487b7160e01b600052603260045260246000fd5b6020026020010151600a6000858481518110610eb257634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908360ff1602179055505b80610efd816129b2565b915050610de2565b507fa8ebc437633f921c0b85258fb33b74715331194b7fdc1627091b38ce0ea7afd48282604051610f3792919061275c565b60405180910390a15050565b610f6d7f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab958261080e565b50565b6001600160a01b03818116600090815260086020526040812054909116610f98576000610f9c565b6007545b610808906127106128bd565b600381511080610fb95750600f8151115b15610ff0576040517f6606a46200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600c60205260409020805461100a90612977565b159050611043576040517fad51e20300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61104c3361174d565b60ff1661106c576040516338b729c360e11b815260040160405180910390fd5b60006001600160a01b0316600b826040516110879190612624565b908152604051908190036020019020546001600160a01b0316146110be5760405163096a1aab60e21b815260040160405180910390fd5b336000908152600c60205260408082209051600b916110dc91612640565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039490941693909317909255336000908152600c8252919091208251611128928401906120eb565b5033600b8260405161113a9190612624565b90815260405190819003602001812080546001600160a01b03939093166001600160a01b031990931692909217909155339081907f627a1b03408ad803620768c059b68f695d3740108ac22fd6cdab3c887b162cbe9061119b908590612835565b60405180910390a350565b610f6d8133610838565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff1661123f5760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b6040516001600160a01b038216907fc44f7b4fe9d29c078d207864fd556e8b68e1759e3ac4ee9cece99d2ec03c27c690600090a2600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000806000806112a4856118a8565b6112af9060016128d5565b9050600060016002546112c29190612919565b8260ff1610156112d257816112e1565b60016002546112e19190612919565b90506112ec81610c09565b94509450945050509193909250565b60006006600061130a8461174d565b60ff168152602001908152602001600020549050919050565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff166113b25760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b60006001600160a01b0316600b826040516113cd9190612624565b908152604051908190036020019020546001600160a01b0316146114045760405163096a1aab60e21b815260040160405180910390fd5b6001600160a01b0382166000908152600c60205260408082209051600b9161142b91612640565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039485161790559184166000908152600c8252919091208251611474928401906120eb565b5081600b826040516114869190612624565b90815260405190819003602001812080546001600160a01b039384166001600160a01b03199091161790559083169033907f627a1b03408ad803620768c059b68f695d3740108ac22fd6cdab3c887b162cbe906114e4908590612835565b60405180910390a35050565b3360009081527fa54247010af6b3693b80aceddfad12e077c5de3571e6243fada502635f0d7d39602052604090205460ff1661157f5760405162461bcd60e51b815260206004820152602860248201527f4d61696e7461696e61626c653a2043616c6c6572206973206e6f742061206d6160448201526734b73a30b4b732b960c11b60648201526084016108b2565b600d5460ff16156115bc576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d805460ff19166001179055604080517f4e606c470000000000000000000000000000000000000000000000000000000081529051734300000000000000000000000000000000000002918291634e606c479160048082019260009290919082900301818387803b15801561163157600080fd5b505af1158015611645573d6000803e3d6000fd5b50506040517feb8646980000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416925063eb8646989150602401600060405180830381600087803b1580156116a557600080fd5b505af11580156116b9573d6000803e3d6000fd5b5050600d80546001600160a01b03909516610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff90951694909417909355505050565b60008281526020819052604090206001015461171981611d11565b6108338383611db9565b610f6d7f339759585899103d2ace64958e37e18ccb0504652c81d4a1b8aa80fe2126ab95826116fe565b6001600160a01b0381166000908152600a602052604081205460ff16156117ce57600160025461177d9190612919565b6001600160a01b0383166000908152600a602052604090205460ff16116117bf576001600160a01b0382166000908152600a602052604090205460ff16610808565b60016002546108089190612919565b610808826118a8565b6001600160a01b038082166000908152600860209081526040808320549093168252600c90522080546060919061180d90612977565b80601f016020809104026020016040519081016040528092919081815260200182805461183990612977565b80156118865780601f1061185b57610100808354040283529160200191611886565b820191906000526020600020905b81548152906001019060200180831161186957829003601f168201915b50505050509050919050565b61189d60008261080e565b610f6d600033610838565b6001546000906001600160a01b03166118c357506000919050565b6001546040517f8ba17f860000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526000928392911690638ba17f869060240160606040518083038186803b15801561192557600080fd5b505afa158015611939573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195d91906125a3565b509150915060005b6002548160ff161015611a2d57600460006119818360016128d5565b60ff168152602001908152602001600020548310156119a257949350505050565b600360006119b18360016128d5565b60ff168152602001908152602001600020548210156119d257949350505050565b600560006119e18360016128d5565b60ff16815260208082019290925260409081016000908120546001600160a01b0389168252600990935220541015611a1b57949350505050565b80611a25816129cd565b915050611965565b50506002549392505050565b60006001600160a01b03831615611a505782611a7a565b600b82604051611a609190612624565b908152604051908190036020019020546001600160a01b03165b90506001600160a01b038116611abc576040517fcd2d66aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116331415611aff576040517f55e8f70e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546001600160a01b0382811691161415611b54576040517ffe1ffa9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0381811660009081526008602052604090205416331415611b8f5760405163b6ea0b0160e01b815260040160405180910390fd5b6001600160a01b03818116600090815260086020526040808220548316825290205416331415611bd25760405163b6ea0b0160e01b815260040160405180910390fd5b611bdb8161174d565b60ff16611bfb576040516338b729c360e11b815260040160405180910390fd5b336000908152600860205260409020546001600160a01b031615801590611c485750336000908152600860209081526040808320546001600160a01b031683526009909152902054600111155b15611c8957336000908152600860209081526040808320546001600160a01b0316835260099091528120805460019290611c83908490612919565b90915550505b33600090815260086020908152604080832080546001600160a01b0319166001600160a01b038616908117909155835260099091528120805460019290611cd19084906128bd565b90915550506040516001600160a01b0382169033907f82ca166ebb8d22637409e8fcca994e7e1b757a1e28f0ee91f4defe3cff1e919390600090a3505050565b610f6d8133611e38565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166108c5576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055611d753390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16156108c5576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166108c557611e6981611eab565b611e74836020611ebd565b604051602001611e859291906126db565b60408051601f198184030181529082905262461bcd60e51b82526108b291600401612835565b60606108086001600160a01b03831660145b60606000611ecc8360026128fa565b611ed79060026128bd565b67ffffffffffffffff811115611efd57634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015611f27576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611f6c57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611fc557634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a9053506000611fe98460026128fa565b611ff49060016128bd565b90505b6001811115612095577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061204357634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061206757634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c9361208e81612960565b9050611ff7565b5083156120e45760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108b2565b9392505050565b8280546120f790612977565b90600052602060002090601f016020900481019282612119576000855561215f565b82601f1061213257805160ff191683800117855561215f565b8280016001018555821561215f579182015b8281111561215f578251825591602001919060010190612144565b5061216b92915061216f565b5090565b5b8082111561216b5760008155600101612170565b80356001600160a01b038116811461219b57600080fd5b919050565b600082601f8301126121b0578081fd5b813560206121c56121c083612899565b612868565b80838252828201915082860187848660051b89010111156121e4578586fd5b855b85811015612202578135845292840192908401906001016121e6565b5090979650505050505050565b600082601f83011261221f578081fd5b8135602061222f6121c083612899565b80838252828201915082860187848660051b890101111561224e578586fd5b855b8581101561220257612261826122de565b84529284019290840190600101612250565b600082601f830112612283578081fd5b813567ffffffffffffffff81111561229d5761229d612a03565b6122b0601f8201601f1916602001612868565b8181528460208386010111156122c4578283fd5b816020850160208301379081016020019190915292915050565b803560ff8116811461219b57600080fd5b600060208284031215612300578081fd5b6120e482612184565b6000806040838503121561231b578081fd5b61232483612184565b9150602083013567ffffffffffffffff81111561233f578182fd5b61234b85828601612273565b9150509250929050565b60008060408385031215612367578182fd5b61237083612184565b915061237e602084016122de565b90509250929050565b60008060408385031215612399578182fd5b823567ffffffffffffffff808211156123b0578384fd5b818501915085601f8301126123c3578384fd5b813560206123d36121c083612899565b8083825282820191508286018a848660051b89010111156123f2578889fd5b8896505b8487101561241b5761240781612184565b8352600196909601959183019183016123f6565b5096505086013592505080821115612431578283fd5b5061234b8582860161220f565b600080600080600060a08688031215612455578081fd5b853567ffffffffffffffff8082111561246c578283fd5b61247889838a016121a0565b9650602088013591508082111561248d578283fd5b61249989838a016121a0565b955060408801359150808211156124ae578283fd5b6124ba89838a016121a0565b945060608801359150808211156124cf578283fd5b506124dc888289016121a0565b95989497509295608001359392505050565b6000602082840312156124ff578081fd5b5035919050565b60008060408385031215612518578182fd5b8235915061237e60208401612184565b600060208284031215612539578081fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146120e4578182fd5b600060208284031215612579578081fd5b813567ffffffffffffffff81111561258f578182fd5b61259b84828501612273565b949350505050565b6000806000606084860312156125b7578081fd5b8351925060208401519150604084015190509250925092565b6000602082840312156125e1578081fd5b6120e4826122de565b6000815180845260208085019450808401835b83811015612619578151875295820195908201906001016125fd565b509495945050505050565b60008251612636818460208701612930565b9190910192915050565b600080835482600182811c91508083168061265c57607f831692505b602080841082141561267c57634e487b7160e01b87526022600452602487fd5b81801561269057600181146126a1576126cd565b60ff198616895284890196506126cd565b60008a815260209020885b868110156126c55781548b8201529085019083016126ac565b505084890196505b509498975050505050505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351612713816017850160208801612930565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351612750816028840160208801612930565b01602801949350505050565b604080825283519082018190526000906020906060840190828701845b8281101561279e5781516001600160a01b031684529284019290840190600101612779565b50505083810382850152845180825285830191830190845b8181101561220257835160ff16835292840192918401916001016127b6565b60a0815260006127e860a08301886125ea565b82810360208401526127fa81886125ea565b9050828103604084015261280e81876125ea565b9050828103606084015261282281866125ea565b9150508260808301529695505050505050565b6020815260008251806020840152612854816040850160208701612930565b601f01601f19169190910160400192915050565b604051601f8201601f1916810167ffffffffffffffff8111828210171561289157612891612a03565b604052919050565b600067ffffffffffffffff8211156128b3576128b3612a03565b5060051b60200190565b600082198211156128d0576128d06129ed565b500190565b600060ff821660ff84168060ff038211156128f2576128f26129ed565b019392505050565b6000816000190483118215151615612914576129146129ed565b500290565b60008282101561292b5761292b6129ed565b500390565b60005b8381101561294b578181015183820152602001612933565b8381111561295a576000848401525b50505050565b60008161296f5761296f6129ed565b506000190190565b600181811c9082168061298b57607f821691505b602082108114156129ac57634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156129c6576129c66129ed565b5060010190565b600060ff821660ff8114156129e4576129e46129ed565b60010192915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fdfea264697066735822122081cb55390721778e5ebde06ffdba4100e63be4df1d04c411eb635601e1b13d2164736f6c63430008040033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$40.92
Net Worth in ETH
0.014057
Token Allocations
ETH
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $2,909.31 | 0.0141 | $40.92 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.