Overview
xDAI Balance
xDAI Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Update Accumulat... | 37592030 | 58 days ago | IN | 0 xDAI | 0.00015207 |
View more zero value Internal Transactions in Advanced View mode
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
LendingManager
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {ILendingManager} from './interfaces/ILendingManager.sol'; import {ILendingModule} from './interfaces/ILendingModule.sol'; import {ILendingStorageManager} from './interfaces/ILendingStorageManager.sol'; import {ISynthereumFinder} from '../core/interfaces/IFinder.sol'; import {SynthereumInterfaces} from '../core/Constants.sol'; import {ISynthereumLendingTransfer} from '../synthereum-pool/common/interfaces/ILendingTransfer.sol'; import {ISynthereumLendingRewards} from '../synthereum-pool/common/interfaces/ILendingRewards.sol'; import {PreciseUnitMath} from '../base/utils/PreciseUnitMath.sol'; import {Address} from '../../@openzeppelin/contracts/utils/Address.sol'; import {IERC20} from '../../@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {SafeERC20} from '../../@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import {SynthereumFactoryAccess} from '../common/libs/FactoryAccess.sol'; import {AccessControlEnumerable} from '../../@openzeppelin/contracts/access/AccessControlEnumerable.sol'; import {ReentrancyGuard} from '../../@openzeppelin/contracts/security/ReentrancyGuard.sol'; contract LendingManager is ILendingManager, ReentrancyGuard, AccessControlEnumerable { using Address for address; using SafeERC20 for IERC20; using PreciseUnitMath for uint256; ISynthereumFinder immutable synthereumFinder; bytes32 public constant MAINTAINER_ROLE = keccak256('Maintainer'); string private constant DEPOSIT_SIG = 'deposit((bytes32,uint256,uint256,uint256,address,uint64,address,uint64),bytes,uint256)'; string private constant WITHDRAW_SIG = 'withdraw((bytes32,uint256,uint256,uint256,address,uint64,address,uint64),address,bytes,uint256,address)'; string private JRTSWAP_SIG = 'swapToJRT(address,address,address,uint256,bytes)'; string private TOTAL_TRANSFER_SIG = 'totalTransfer(address,address,address,address,bytes)'; modifier onlyMaintainer() { require( hasRole(MAINTAINER_ROLE, msg.sender), 'Sender must be the maintainer' ); _; } modifier onlyPoolFactory() { SynthereumFactoryAccess._onlyPoolFactory(synthereumFinder); _; } constructor(ISynthereumFinder _finder, Roles memory _roles) nonReentrant { synthereumFinder = _finder; _setRoleAdmin(DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_ROLE); _setRoleAdmin(MAINTAINER_ROLE, DEFAULT_ADMIN_ROLE); _setupRole(DEFAULT_ADMIN_ROLE, _roles.admin); _setupRole(MAINTAINER_ROLE, _roles.maintainer); } function deposit(uint256 _amount) external override nonReentrant returns (ReturnValues memory returnValues) { ( ILendingStorageManager.PoolStorage memory poolData, ILendingStorageManager.LendingInfo memory lendingInfo, ILendingStorageManager poolStorageManager ) = _getPoolInfo(); // delegate call implementation bytes memory result = address(lendingInfo.lendingModule) .functionDelegateCall( abi.encodeWithSignature(DEPOSIT_SIG, poolData, lendingInfo.args, _amount) ); ILendingModule.ReturnValues memory res = abi.decode( result, (ILendingModule.ReturnValues) ); // split interest InterestSplit memory interestSplit = splitGeneratedInterest( res.totalInterest, poolData.daoInterestShare, poolData.jrtBuybackShare ); // update pool storage values poolStorageManager.updateValues( msg.sender, poolData.collateralDeposited + res.tokensOut + interestSplit.poolInterest, poolData.unclaimedDaoJRT + interestSplit.jrtInterest, poolData.unclaimedDaoCommission + interestSplit.commissionInterest ); // set return values returnValues.tokensOut = res.tokensOut; returnValues.tokensTransferred = res.tokensTransferred; returnValues.poolInterest = interestSplit.poolInterest; returnValues.daoInterest = interestSplit.commissionInterest + interestSplit.jrtInterest; returnValues.prevTotalCollateral = poolData.collateralDeposited; } function withdraw(uint256 _interestTokenAmount, address _recipient) external override nonReentrant returns (ReturnValues memory returnValues) { ( ILendingStorageManager.PoolStorage memory poolData, ILendingStorageManager.LendingInfo memory lendingInfo, ILendingStorageManager poolStorageManager ) = _getPoolInfo(); // delegate call implementation bytes memory result = address(lendingInfo.lendingModule) .functionDelegateCall( abi.encodeWithSignature( WITHDRAW_SIG, poolData, msg.sender, lendingInfo.args, _interestTokenAmount, _recipient ) ); ILendingModule.ReturnValues memory res = abi.decode( result, (ILendingModule.ReturnValues) ); // split interest InterestSplit memory interestSplit = splitGeneratedInterest( res.totalInterest, poolData.daoInterestShare, poolData.jrtBuybackShare ); // update storage value poolStorageManager.updateValues( msg.sender, poolData.collateralDeposited + interestSplit.poolInterest - res.tokensOut, poolData.unclaimedDaoJRT + interestSplit.jrtInterest, poolData.unclaimedDaoCommission + interestSplit.commissionInterest ); // set return values returnValues.tokensOut = res.tokensOut; returnValues.tokensTransferred = res.tokensTransferred; returnValues.poolInterest = interestSplit.poolInterest; returnValues.daoInterest = interestSplit.commissionInterest + interestSplit.jrtInterest; returnValues.prevTotalCollateral = poolData.collateralDeposited; } function updateAccumulatedInterest() external override nonReentrant returns (ReturnValues memory returnValues) { ( ILendingStorageManager.PoolStorage memory poolData, ILendingStorageManager.LendingInfo memory lendingInfo, ILendingStorageManager poolStorageManager ) = _getPoolInfo(); // retrieve accumulated interest uint256 totalInterest = ILendingModule(lendingInfo.lendingModule) .getUpdatedInterest(msg.sender, poolData, lendingInfo.args); // split according to shares InterestSplit memory interestSplit = splitGeneratedInterest( totalInterest, poolData.daoInterestShare, poolData.jrtBuybackShare ); //update pool storage poolStorageManager.updateValues( msg.sender, poolData.collateralDeposited + interestSplit.poolInterest, poolData.unclaimedDaoJRT + interestSplit.jrtInterest, poolData.unclaimedDaoCommission + interestSplit.commissionInterest ); // return values returnValues.poolInterest = interestSplit.poolInterest; returnValues.daoInterest = interestSplit.jrtInterest + interestSplit.commissionInterest; returnValues.prevTotalCollateral = poolData.collateralDeposited; } function batchClaimCommission( address[] calldata _pools, uint256[] calldata _amounts ) external override onlyMaintainer { require(_pools.length == _amounts.length, 'Invalid call'); address recipient = synthereumFinder.getImplementationAddress( SynthereumInterfaces.CommissionReceiver ); uint256 totalAmount; for (uint8 i = 0; i < _pools.length; i++) { if (_amounts[i] > 0) { claimCommission(_pools[i], _amounts[i], recipient); totalAmount += _amounts[i]; } } emit BatchCommissionClaim(totalAmount, recipient); } function batchBuyback( address[] calldata _pools, uint256[] calldata _amounts, address _collateralAddress, bytes calldata _swapParams ) external override onlyMaintainer { require(_pools.length == _amounts.length, 'Invalid call'); ILendingStorageManager poolStorageManager = getStorageManager(); // withdraw collateral and update all pools uint256 aggregatedCollateral; address recipient = synthereumFinder.getImplementationAddress( SynthereumInterfaces.BuybackProgramReceiver ); for (uint8 i = 0; i < _pools.length; i++) { address pool = _pools[i]; uint256 _collateralAmount = _amounts[i]; ( ILendingStorageManager.PoolStorage memory poolData, ILendingStorageManager.LendingInfo memory lendingInfo ) = poolStorageManager.getPoolData(pool); // all pools need to have the same collateral require(poolData.collateral == _collateralAddress, 'Collateral mismatch'); (uint256 interestTokenAmount, ) = collateralToInterestToken( pool, _collateralAmount ); // trigger transfer of interest token from the pool interestTokenAmount = ISynthereumLendingTransfer(pool) .transferToLendingManager(interestTokenAmount); bytes memory withdrawRes = address(lendingInfo.lendingModule) .functionDelegateCall( abi.encodeWithSignature( WITHDRAW_SIG, poolData, pool, lendingInfo.args, interestTokenAmount, address(this) ) ); ILendingModule.ReturnValues memory res = abi.decode( withdrawRes, (ILendingModule.ReturnValues) ); // update aggregated collateral to use for buyback aggregatedCollateral += res.tokensTransferred; // split interest InterestSplit memory interestSplit = splitGeneratedInterest( res.totalInterest, poolData.daoInterestShare, poolData.jrtBuybackShare ); //update pool storage poolStorageManager.updateValues( pool, poolData.collateralDeposited + interestSplit.poolInterest, poolData.unclaimedDaoJRT + interestSplit.jrtInterest - res.tokensOut, poolData.unclaimedDaoCommission + interestSplit.commissionInterest ); } // execute the buyback call with all the withdrawn collateral address JARVIS = synthereumFinder.getImplementationAddress( SynthereumInterfaces.JarvisToken ); bytes memory result = address( poolStorageManager.getCollateralSwapModule(_collateralAddress) ).functionDelegateCall( abi.encodeWithSignature( JRTSWAP_SIG, recipient, _collateralAddress, JARVIS, aggregatedCollateral, _swapParams ) ); emit BatchBuyback( aggregatedCollateral, abi.decode(result, (uint256)), recipient ); } function setLendingModule( string calldata _id, ILendingStorageManager.LendingInfo calldata _lendingInfo ) external override onlyMaintainer nonReentrant { ILendingStorageManager poolStorageManager = getStorageManager(); poolStorageManager.setLendingModule(_id, _lendingInfo); } function addSwapProtocol(address _swapModule) external override onlyMaintainer nonReentrant { ILendingStorageManager poolStorageManager = getStorageManager(); poolStorageManager.addSwapProtocol(_swapModule); } function removeSwapProtocol(address _swapModule) external override onlyMaintainer nonReentrant { ILendingStorageManager poolStorageManager = getStorageManager(); poolStorageManager.removeSwapProtocol(_swapModule); } function setSwapModule(address _collateral, address _swapModule) external override onlyMaintainer nonReentrant { ILendingStorageManager poolStorageManager = getStorageManager(); poolStorageManager.setSwapModule(_collateral, _swapModule); } function setShares( address _pool, uint64 _daoInterestShare, uint64 _jrtBuybackShare ) external override onlyMaintainer nonReentrant { ILendingStorageManager poolStorageManager = getStorageManager(); poolStorageManager.setShares(_pool, _daoInterestShare, _jrtBuybackShare); } // to migrate liquidity to another lending module function migrateLendingModule( string memory _newLendingID, address _newInterestBearingToken, uint256 _interestTokenAmount ) external override nonReentrant returns (MigrateReturnValues memory) { ( ILendingStorageManager.PoolStorage memory poolData, ILendingStorageManager.LendingInfo memory lendingInfo, ILendingStorageManager poolStorageManager ) = _getPoolInfo(); uint256 prevDepositedCollateral = poolData.collateralDeposited; // delegate call withdraw collateral from old module ILendingModule.ReturnValues memory res; { bytes memory withdrawRes = address(lendingInfo.lendingModule) .functionDelegateCall( abi.encodeWithSignature( WITHDRAW_SIG, poolData, msg.sender, lendingInfo.args, _interestTokenAmount, address(this) ) ); res = abi.decode(withdrawRes, (ILendingModule.ReturnValues)); } // split interest InterestSplit memory interestSplit = splitGeneratedInterest( res.totalInterest, poolData.daoInterestShare, poolData.jrtBuybackShare ); // add interest to pool data uint256 newDaoJRT = poolData.unclaimedDaoJRT + interestSplit.jrtInterest; uint256 newDaoCommission = poolData.unclaimedDaoCommission + interestSplit.commissionInterest; // temporary set pool data collateral and interest to 0 to freshly deposit poolStorageManager.updateValues(msg.sender, 0, 0, 0); // set new lending module and obtain new pool data ILendingStorageManager.LendingInfo memory newLendingInfo; (poolData, newLendingInfo) = poolStorageManager.migrateLendingModule( _newLendingID, msg.sender, _newInterestBearingToken ); // delegate call deposit into new module bytes memory result = address(newLendingInfo.lendingModule) .functionDelegateCall( abi.encodeWithSignature( DEPOSIT_SIG, poolData, newLendingInfo.args, res.tokensTransferred, msg.sender ) ); ILendingModule.ReturnValues memory depositRes = abi.decode( result, (ILendingModule.ReturnValues) ); // update storage with accumulated interest uint256 actualCollateralDeposited = depositRes.tokensOut - newDaoJRT - newDaoCommission; poolStorageManager.updateValues( msg.sender, actualCollateralDeposited, newDaoJRT, newDaoCommission ); return ( MigrateReturnValues( prevDepositedCollateral, interestSplit.poolInterest, actualCollateralDeposited ) ); } function migratePool(address _migrationPool, address _newPool) external override onlyPoolFactory nonReentrant returns (uint256 sourceCollateralAmount, uint256 actualCollateralAmount) { ILendingStorageManager poolStorageManager = getStorageManager(); ( ILendingStorageManager.PoolLendingStorage memory lendingStorage, ILendingStorageManager.LendingInfo memory lendingInfo ) = poolStorageManager.getLendingData(_migrationPool); // delegate call deposit into new module bytes memory result = address(lendingInfo.lendingModule) .functionDelegateCall( abi.encodeWithSignature( TOTAL_TRANSFER_SIG, _migrationPool, _newPool, lendingStorage.collateralToken, lendingStorage.interestToken, lendingInfo.args ) ); (uint256 prevTotalAmount, uint256 newTotalAmount) = abi.decode( result, (uint256, uint256) ); sourceCollateralAmount = poolStorageManager.getCollateralDeposited( _migrationPool ); actualCollateralAmount = sourceCollateralAmount + newTotalAmount - prevTotalAmount; poolStorageManager.migratePoolStorage( _migrationPool, _newPool, actualCollateralAmount ); } function claimLendingRewards(address[] calldata _pools) external override onlyMaintainer nonReentrant { ILendingStorageManager poolStorageManager = getStorageManager(); ILendingStorageManager.PoolLendingStorage memory poolLendingStorage; ILendingStorageManager.LendingInfo memory lendingInfo; address recipient = synthereumFinder.getImplementationAddress( SynthereumInterfaces.LendingRewardsReceiver ); for (uint8 i = 0; i < _pools.length; i++) { (poolLendingStorage, lendingInfo) = poolStorageManager.getLendingData( _pools[i] ); ISynthereumLendingRewards(_pools[i]).claimLendingRewards( lendingInfo, poolLendingStorage, recipient ); } } function interestTokenToCollateral( address _pool, uint256 _interestTokenAmount ) external view override returns (uint256 collateralAmount, address interestTokenAddr) { ILendingStorageManager poolStorageManager = getStorageManager(); ( ILendingStorageManager.PoolLendingStorage memory lendingStorage, ILendingStorageManager.LendingInfo memory lendingInfo ) = poolStorageManager.getLendingData(_pool); collateralAmount = ILendingModule(lendingInfo.lendingModule) .interestTokenToCollateral( _interestTokenAmount, lendingStorage.collateralToken, lendingStorage.interestToken, lendingInfo.args ); interestTokenAddr = lendingStorage.interestToken; } function getAccumulatedInterest(address _pool) external view override returns ( uint256 poolInterest, uint256 commissionInterest, uint256 buybackInterest, uint256 collateralDeposited ) { ILendingStorageManager poolStorageManager = getStorageManager(); ( ILendingStorageManager.PoolStorage memory poolData, ILendingStorageManager.LendingInfo memory lendingInfo ) = poolStorageManager.getPoolData(_pool); uint256 totalInterest = ILendingModule(lendingInfo.lendingModule) .getAccumulatedInterest(_pool, poolData, lendingInfo.args); InterestSplit memory interestSplit = splitGeneratedInterest( totalInterest, poolData.daoInterestShare, poolData.jrtBuybackShare ); poolInterest = interestSplit.poolInterest; commissionInterest = interestSplit.commissionInterest; buybackInterest = interestSplit.jrtInterest; collateralDeposited = poolData.collateralDeposited; } function collateralToInterestToken(address _pool, uint256 _collateralAmount) public view override returns (uint256 interestTokenAmount, address interestTokenAddr) { ILendingStorageManager poolStorageManager = getStorageManager(); ( ILendingStorageManager.PoolLendingStorage memory lendingStorage, ILendingStorageManager.LendingInfo memory lendingInfo ) = poolStorageManager.getLendingData(_pool); interestTokenAmount = ILendingModule(lendingInfo.lendingModule) .collateralToInterestToken( _collateralAmount, lendingStorage.collateralToken, lendingStorage.interestToken, lendingInfo.args ); interestTokenAddr = lendingStorage.interestToken; } function claimCommission( address _pool, uint256 _collateralAmount, address _recipient ) internal { ILendingStorageManager poolStorageManager = getStorageManager(); ( ILendingStorageManager.PoolStorage memory poolData, ILendingStorageManager.LendingInfo memory lendingInfo ) = poolStorageManager.getPoolData(_pool); // trigger transfer of funds from _pool (uint256 interestTokenAmount, ) = collateralToInterestToken( _pool, _collateralAmount ); interestTokenAmount = ISynthereumLendingTransfer(_pool) .transferToLendingManager(interestTokenAmount); // delegate call withdraw bytes memory result = address(lendingInfo.lendingModule) .functionDelegateCall( abi.encodeWithSignature( WITHDRAW_SIG, poolData, _pool, lendingInfo.args, interestTokenAmount, _recipient ) ); ILendingModule.ReturnValues memory res = abi.decode( result, (ILendingModule.ReturnValues) ); // split interest InterestSplit memory interestSplit = splitGeneratedInterest( res.totalInterest, poolData.daoInterestShare, poolData.jrtBuybackShare ); //update pool storage poolStorageManager.updateValues( _pool, poolData.collateralDeposited + interestSplit.poolInterest, poolData.unclaimedDaoJRT + interestSplit.jrtInterest, poolData.unclaimedDaoCommission + interestSplit.commissionInterest - res.tokensOut ); } function _getPoolInfo() internal view returns ( ILendingStorageManager.PoolStorage memory poolData, ILendingStorageManager.LendingInfo memory lendingInfo, ILendingStorageManager poolStorageManager ) { poolStorageManager = getStorageManager(); (poolData, lendingInfo) = poolStorageManager.getPoolData(msg.sender); } function getStorageManager() internal view returns (ILendingStorageManager) { return ILendingStorageManager( synthereumFinder.getImplementationAddress( SynthereumInterfaces.LendingStorageManager ) ); } function splitGeneratedInterest( uint256 _totalInterestGenerated, uint64 _daoRatio, uint64 _jrtRatio ) internal pure returns (InterestSplit memory interestSplit) { if (_totalInterestGenerated == 0) return interestSplit; uint256 daoInterest = _totalInterestGenerated.mul(_daoRatio); interestSplit.jrtInterest = daoInterest.mul(_jrtRatio); interestSplit.commissionInterest = daoInterest - interestSplit.jrtInterest; interestSplit.poolInterest = _totalInterestGenerated - daoInterest; } }
// SPDX-License-Identifier: MIT 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: * * ``` * 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}: * * ``` * 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. */ 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, _msgSender()); _; } /** * @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 override returns (bool) { return _roles[role].members[account]; } /** * @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 { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(uint160(account), 20), " 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 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. */ 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. */ 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 granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ 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. * * [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}. * ==== */ 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); } function _grantRole(bytes32 role, address account) private { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } function _revokeRole(bytes32 role, address account) private { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT 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 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; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @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] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT 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 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 pragma solidity ^0.8.0; import "./IAccessControlEnumerable.sol"; import "./AccessControl.sol"; import "../utils/structs/EnumerableSet.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. */ abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { using EnumerableSet for EnumerableSet.AddressSet; mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view override returns (address) { return _roleMembers[role].at(index); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view override returns (uint256) { return _roleMembers[role].length(); } /** * @dev Overload {grantRole} to track enumerable memberships */ function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { super.grantRole(role, account); _roleMembers[role].add(account); } /** * @dev Overload {revokeRole} to track enumerable memberships */ function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { super.revokeRole(role, account); _roleMembers[role].remove(account); } /** * @dev Overload {renounceRole} to track enumerable memberships */ function renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { super.renounceRole(role, account); _roleMembers[role].remove(account); } /** * @dev Overload {_setupRole} to track enumerable memberships */ function _setupRole(bytes32 role, address account) internal virtual override { super._setupRole(role, account); _roleMembers[role].add(account); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IAccessControl.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IAccessControlEnumerable is IAccessControl { /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) external view returns (address); /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) external view returns (uint256); }
// SPDX-License-Identifier: MIT 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. * * ``` * 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. */ 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) { return _values(set._inner); } // 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; 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 on 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; assembly { result := store } return result; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ILendingStorageManager} from './ILendingStorageManager.sol'; interface ILendingManager { struct Roles { address admin; address maintainer; } struct ReturnValues { uint256 poolInterest; //accumulated pool interest since last state-changing operation; uint256 daoInterest; //acccumulated dao interest since last state-changing operation; uint256 tokensOut; //amount of collateral used for a money market operation uint256 tokensTransferred; //amount of tokens finally transfered/received from money market (after eventual fees) uint256 prevTotalCollateral; //total collateral in the pool (users + LPs) before new operation } struct InterestSplit { uint256 poolInterest; // share of the total interest generated to the LPs; uint256 jrtInterest; // share of the total interest generated for jrt buyback; uint256 commissionInterest; // share of the total interest generated as dao commission; } struct MigrateReturnValues { uint256 prevTotalCollateral; // prevDepositedCollateral collateral deposited (without last interests) before the migration uint256 poolInterest; // poolInterests collateral interests accumalated before the migration uint256 actualTotalCollateral; // actualCollateralDeposited collateral deposited after the migration } event BatchBuyback( uint256 indexed collateralIn, uint256 JRTOut, address receiver ); event BatchCommissionClaim(uint256 indexed collateralOut, address receiver); /** * @notice deposits collateral into the pool's associated money market * @dev calculates and return the generated interest since last state-changing operation * @param _collateralAmount amount of collateral to deposit * @return returnValues check struct */ function deposit(uint256 _collateralAmount) external returns (ReturnValues memory returnValues); /** * @notice withdraw collateral from the pool's associated money market * @dev calculates and return the generated interest since last state-changing operation * @param _interestTokenAmount amount of interest tokens to redeem * @param _recipient the address receiving the collateral from money market * @return returnValues check struct */ function withdraw(uint256 _interestTokenAmount, address _recipient) external returns (ReturnValues memory returnValues); /** * @notice calculate, split and update the generated interest of the caller pool since last state-changing operation * @return returnValues check struct */ function updateAccumulatedInterest() external returns (ReturnValues memory returnValues); /** * @notice batches calls to redeem poolData.commissionInterest from multiple pools * @dev calculates and update the generated interest since last state-changing operation * @param _pools array of pools to redeem commissions from * @param _collateralAmounts array of amount of commission to redeem for each pool (matching pools order) */ function batchClaimCommission( address[] calldata _pools, uint256[] calldata _collateralAmounts ) external; /** * @notice batches calls to redeem poolData.jrtInterest from multiple pools * @notice and executes a swap to buy Jarvis Reward Token * @dev calculates and update the generated interest since last state-changing operation * @param _pools array of pools to redeem collateral from * @param _collateralAmounts array of amount of commission to redeem for each pool (matching pools order) * @param _collateralAddress address of the pools collateral token (all pools must have the same collateral) * @param _swapParams encoded bytes necessary for the swap module */ function batchBuyback( address[] calldata _pools, uint256[] calldata _collateralAmounts, address _collateralAddress, bytes calldata _swapParams ) external; /** * @notice sets the address of the implementation of a lending module and its extraBytes * @param _id associated to the lending module to be set * @param _lendingInfo see lendingInfo struct */ function setLendingModule( string calldata _id, ILendingStorageManager.LendingInfo calldata _lendingInfo ) external; /** * @notice Add a swap module to the whitelist * @param _swapModule Swap module to add */ function addSwapProtocol(address _swapModule) external; /** * @notice Remove a swap module from the whitelist * @param _swapModule Swap module to remove */ function removeSwapProtocol(address _swapModule) external; /** * @notice sets an address as the swap module associated to a specific collateral * @dev the swapModule must implement the IJRTSwapModule interface * @param _collateral collateral address associated to the swap module * @param _swapModule IJRTSwapModule implementer contract */ function setSwapModule(address _collateral, address _swapModule) external; /** * @notice set shares on interest generated by a pool collateral on the lending storage manager * @param _pool pool address to set shares on * @param _daoInterestShare share of total interest generated assigned to the dao * @param _jrtBuybackShare share of the total dao interest used to buyback jrt from an AMM */ function setShares( address _pool, uint64 _daoInterestShare, uint64 _jrtBuybackShare ) external; /** * @notice migrates liquidity from one lending module (and money market), to a new one * @dev calculates and return the generated interest since last state-changing operation. * @dev The new lending module info must be have been previously set in the storage manager * @param _newLendingID id associated to the new lending module info * @param _newInterestBearingToken address of the interest token of the new money market * @param _interestTokenAmount total amount of interest token to migrate from old to new money market * @return migrateReturnValues check struct */ function migrateLendingModule( string memory _newLendingID, address _newInterestBearingToken, uint256 _interestTokenAmount ) external returns (MigrateReturnValues memory); /** * @notice migrates pool storage from a deployed pool to a new pool * @param _migrationPool Pool from which the storage is migrated * @param _newPool address of the new pool * @return sourceCollateralAmount Collateral amount of the pool to migrate * @return actualCollateralAmount Collateral amount of the new deployed pool */ function migratePool(address _migrationPool, address _newPool) external returns (uint256 sourceCollateralAmount, uint256 actualCollateralAmount); /** * @notice Claim leinding protocol rewards of a list of pools * @notice _pools List of pools from which claim rewards */ function claimLendingRewards(address[] calldata _pools) external; /** * @notice returns the conversion between interest token and collateral of a specific money market * @param _pool reference pool to check conversion * @param _interestTokenAmount amount of interest token to calculate conversion on * @return collateralAmount amount of collateral after conversion * @return interestTokenAddr address of the associated interest token */ function interestTokenToCollateral( address _pool, uint256 _interestTokenAmount ) external view returns (uint256 collateralAmount, address interestTokenAddr); /** * @notice returns accumulated interest of a pool since state-changing last operation * @dev does not update state * @param _pool reference pool to check accumulated interest * @return poolInterest amount of interest generated for the pool after splitting the dao share * @return commissionInterest amount of interest generated for the dao commissions * @return buybackInterest amount of interest generated for the buyback * @return collateralDeposited total amount of collateral currently deposited by the pool */ function getAccumulatedInterest(address _pool) external view returns ( uint256 poolInterest, uint256 commissionInterest, uint256 buybackInterest, uint256 collateralDeposited ); /** * @notice returns the conversion between collateral and interest token of a specific money market * @param _pool reference pool to check conversion * @param _collateralAmount amount of collateral to calculate conversion on * @return interestTokenAmount amount of interest token after conversion * @return interestTokenAddr address of the associated interest token */ function collateralToInterestToken(address _pool, uint256 _collateralAmount) external view returns (uint256 interestTokenAmount, address interestTokenAddr); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ILendingStorageManager} from './ILendingStorageManager.sol'; interface ILendingModule { struct ReturnValues { uint256 totalInterest; // total accumulated interest of the pool since last state-changing operation uint256 tokensOut; //amount of tokens received from money market (before eventual fees) uint256 tokensTransferred; //amount of tokens finally transfered from money market (after eventual fees) } /** * @notice deposits collateral into the money market * @dev calculates and return the generated interest since last state-changing operation * @param _poolData pool storage information * @param _lendingArgs encoded args needed by the specific implementation * @param _amount of collateral to deposit * @return totalInterest check ReturnValues struct * @return tokensOut check ReturnValues struct * @return tokensTransferred check ReturnValues struct */ function deposit( ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata _lendingArgs, uint256 _amount ) external returns ( uint256 totalInterest, uint256 tokensOut, uint256 tokensTransferred ); /** * @notice withdraw collateral from the money market * @dev calculates and return the generated interest since last state-changing operation * @param _poolData pool storage information * @param _pool pool address to calculate interest on * @param _lendingArgs encoded args needed by the specific implementation * @param _amount of interest tokens to redeem * @param _recipient address receiving the collateral from money market * @return totalInterest check ReturnValues struct * @return tokensOut check ReturnValues struct * @return tokensTransferred check ReturnValues struct */ function withdraw( ILendingStorageManager.PoolStorage calldata _poolData, address _pool, bytes calldata _lendingArgs, uint256 _amount, address _recipient ) external returns ( uint256 totalInterest, uint256 tokensOut, uint256 tokensTransferred ); /** * @notice transfer all interest token balance from an old pool to a new one * @param _oldPool Address of the old pool * @param _newPool Address of the new pool * @param _collateral address of collateral token * @param _interestToken address of interest token * @param _extraArgs encoded args the ILendingModule implementer might need. see ILendingManager.LendingInfo struct * @return prevTotalCollateral Total collateral in the old pool * @return actualTotalCollateral Total collateral in the new pool */ function totalTransfer( address _oldPool, address _newPool, address _collateral, address _interestToken, bytes calldata _extraArgs ) external returns (uint256 prevTotalCollateral, uint256 actualTotalCollateral); /** * @notice Claim the rewards associated to the bearing tokens of the caller(pool) * @param _lendingArgs encoded args needed by the specific implementation * @param _collateral Address of the collateral of the pool * @param _bearingToken Address of the bearing token of the pool * @param _recipient address to which send rewards */ function claimRewards( bytes calldata _lendingArgs, address _collateral, address _bearingToken, address _recipient ) external; /** * @notice updates eventual state and returns updated accumulated interest * @param _poolAddress reference pool to check accumulated interest * @param _poolData pool storage information * @param _extraArgs encoded args the ILendingModule implementer might need. see ILendingManager.LendingInfo struct * @return totalInterest total amount of interest accumulated */ function getUpdatedInterest( address _poolAddress, ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata _extraArgs ) external returns (uint256 totalInterest); /** * @notice returns accumulated interest of a pool since state-changing last operation * @dev does not update state * @param _poolAddress reference pool to check accumulated interest * @param _poolData pool storage information * @param _extraArgs encoded args the ILendingModule implementer might need. see ILendingManager.LendingInfo struct * @return totalInterest total amount of interest accumulated */ function getAccumulatedInterest( address _poolAddress, ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata _extraArgs ) external view returns (uint256 totalInterest); /** * @notice returns bearing token associated to the collateral * @dev does not update state * @param _collateral collateral address to check bearing token * @param _extraArgs encoded args the ILendingModule implementer might need. see ILendingManager.LendingInfo struct * @return token bearing token */ function getInterestBearingToken( address _collateral, bytes calldata _extraArgs ) external view returns (address token); /** * @notice returns the conversion between collateral and interest token of a specific money market * @param _collateralAmount amount of collateral to calculate conversion on * @param _collateral address of collateral token * @param _interestToken address of interest token * @param _extraArgs encoded args the ILendingModule implementer might need. see ILendingManager.LendingInfo struct * @return interestTokenAmount amount of interest token after conversion */ function collateralToInterestToken( uint256 _collateralAmount, address _collateral, address _interestToken, bytes calldata _extraArgs ) external view returns (uint256 interestTokenAmount); /** * @notice returns the conversion between interest token and collateral of a specific money market * @param _interestTokenAmount amount of interest token to calculate conversion on * @param _collateral address of collateral token * @param _interestToken address of interest token * @param _extraArgs encoded args the ILendingModule implementer might need. see ILendingManager.LendingInfo struct * @return collateralAmount amount of collateral token after conversion */ function interestTokenToCollateral( uint256 _interestTokenAmount, address _collateral, address _interestToken, bytes calldata _extraArgs ) external view returns (uint256 collateralAmount); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; interface ILendingStorageManager { struct PoolStorage { bytes32 lendingModuleId; // hash of the lending module id associated with the LendingInfo the pool currently is using uint256 collateralDeposited; // amount of collateral currently deposited in the MoneyMarket uint256 unclaimedDaoJRT; // amount of interest to be claimed to buyback JRT uint256 unclaimedDaoCommission; // amount of interest to be claimed as commission (in collateral) address collateral; // collateral address of the pool uint64 jrtBuybackShare; // share of dao interest used to buyback JRT address interestBearingToken; // interest token address of the pool uint64 daoInterestShare; // share of total interest generated by the pool directed to the DAO } struct PoolLendingStorage { address collateralToken; // address of the collateral token of a pool address interestToken; // address of interest token of a pool } struct LendingInfo { address lendingModule; // address of the ILendingModule interface implementer bytes args; // encoded args the ILendingModule implementer might need } /** * @notice sets a ILendingModule implementer info * @param _id string identifying a specific ILendingModule implementer * @param _lendingInfo see lendingInfo struct */ function setLendingModule( string calldata _id, LendingInfo calldata _lendingInfo ) external; /** * @notice Add a swap module to the whitelist * @param _swapModule Swap module to add */ function addSwapProtocol(address _swapModule) external; /** * @notice Remove a swap module from the whitelist * @param _swapModule Swap module to remove */ function removeSwapProtocol(address _swapModule) external; /** * @notice sets an address as the swap module associated to a specific collateral * @dev the swapModule must implement the IJRTSwapModule interface * @param _collateral collateral address associated to the swap module * @param _swapModule IJRTSwapModule implementer contract */ function setSwapModule(address _collateral, address _swapModule) external; /** * @notice set shares on interest generated by a pool collateral on the lending storage manager * @param _pool pool address to set shares on * @param _daoInterestShare share of total interest generated assigned to the dao * @param _jrtBuybackShare share of the total dao interest used to buyback jrt from an AMM */ function setShares( address _pool, uint64 _daoInterestShare, uint64 _jrtBuybackShare ) external; /** * @notice store data for lending manager associated to a pool * @param _lendingID string identifying the associated ILendingModule implementer * @param _pool pool address to set info * @param _collateral collateral address of the pool * @param _interestBearingToken address of the interest token in use * @param _daoInterestShare share of total interest generated assigned to the dao * @param _jrtBuybackShare share of the total dao interest used to buyback jrt from an AMM */ function setPoolStorage( string calldata _lendingID, address _pool, address _collateral, address _interestBearingToken, uint64 _daoInterestShare, uint64 _jrtBuybackShare ) external; /** * @notice assign oldPool storage information and state to newPool address and deletes oldPool storage slot * @dev is used when a pool is redeployed and the liquidity transferred over * @param _oldPool address of old pool to migrate storage from * @param _newPool address of the new pool receiving state of oldPool * @param _newCollateralDeposited Amount of collateral deposited in the new pool after the migration */ function migratePoolStorage( address _oldPool, address _newPool, uint256 _newCollateralDeposited ) external; /** * @notice sets new lending info on a pool * @dev used when migrating liquidity from one lending module (and money market), to a new one * @dev The new lending module info must be have been previously set in the storage manager * @param _newLendingID id associated to the new lending module info * @param _pool address of the pool whose associated lending module is being migrated * @param _newInterestToken address of the interest token of the new Lending Module (can be set blank) * @return poolData with the updated state * @return lendingInfo of the new lending module */ function migrateLendingModule( string calldata _newLendingID, address _pool, address _newInterestToken ) external returns (PoolStorage memory, LendingInfo memory); /** * @notice updates storage of a pool * @dev should be callable only by LendingManager after state-changing operations * @param _pool address of the pool to update values * @param _collateralDeposited updated amount of collateral deposited * @param _daoJRT updated amount of unclaimed interest for JRT buyback * @param _daoInterest updated amount of unclaimed interest as dao commission */ function updateValues( address _pool, uint256 _collateralDeposited, uint256 _daoJRT, uint256 _daoInterest ) external; /** * @notice Returns info about a supported lending module * @param _id Name of the module * @return lendingInfo Address and bytes associated to the lending mdodule */ function getLendingModule(string calldata _id) external view returns (LendingInfo memory lendingInfo); /** * @notice reads PoolStorage of a pool * @param _pool address of the pool to read storage * @return poolData pool struct info */ function getPoolStorage(address _pool) external view returns (PoolStorage memory poolData); /** * @notice reads PoolStorage and LendingInfo of a pool * @param _pool address of the pool to read storage * @return poolData pool struct info * @return lendingInfo information of the lending module associated with the pool */ function getPoolData(address _pool) external view returns (PoolStorage memory poolData, LendingInfo memory lendingInfo); /** * @notice reads lendingStorage and LendingInfo of a pool * @param _pool address of the pool to read storage * @return lendingStorage information of the addresses of collateral and intrestToken * @return lendingInfo information of the lending module associated with the pool */ function getLendingData(address _pool) external view returns ( PoolLendingStorage memory lendingStorage, LendingInfo memory lendingInfo ); /** * @notice Return the list containing every swap module supported * @return List of swap modules */ function getSwapModules() external view returns (address[] memory); /** * @notice reads the JRT Buyback module associated to a collateral * @param _collateral address of the collateral to retrieve module * @return swapModule address of interface implementer of the IJRTSwapModule */ function getCollateralSwapModule(address _collateral) external view returns (address swapModule); /** * @notice reads the interest beaaring token address associated to a pool * @param _pool address of the pool to retrieve interest token * @return interestTokenAddr address of the interest token */ function getInterestBearingToken(address _pool) external view returns (address interestTokenAddr); /** * @notice reads the shares used for splitting interests between pool, dao and buyback * @param _pool address of the pool to retrieve interest token * @return jrtBuybackShare Percentage of interests claimable by th DAO * @return daoInterestShare Percentage of interests used for the buyback */ function getShares(address _pool) external view returns (uint256 jrtBuybackShare, uint256 daoInterestShare); /** * @notice reads the last collateral amount deposited in the pool * @param _pool address of the pool to retrieve collateral amount * @return collateralAmount Amount of collateral deposited in the pool */ function getCollateralDeposited(address _pool) external view returns (uint256 collateralAmount); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /** * @title Provides addresses of the contracts implementing certain interfaces. */ interface ISynthereumFinder { /** * @notice Updates the address of the contract that implements `interfaceName`. * @param interfaceName bytes32 encoding of the interface name that is either changed or registered. * @param implementationAddress address of the deployed contract that implements the interface. */ function changeImplementationAddress( bytes32 interfaceName, address implementationAddress ) external; /** * @notice Gets the address of the contract that implements the given `interfaceName`. * @param interfaceName queried interface. * @return implementationAddress Address of the deployed contract that implements the interface. */ function getImplementationAddress(bytes32 interfaceName) external view returns (address); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; /** * @title Stores common interface names used throughout Synthereum. */ library SynthereumInterfaces { bytes32 public constant Deployer = 'Deployer'; bytes32 public constant PoolRegistry = 'PoolRegistry'; bytes32 public constant SelfMintingRegistry = 'SelfMintingRegistry'; bytes32 public constant FixedRateRegistry = 'FixedRateRegistry'; bytes32 public constant VaultRegistry = 'VaultRegistry'; bytes32 public constant StakingLPVaultRegistry = 'StakingLPVaultRegistry'; bytes32 public constant FactoryVersioning = 'FactoryVersioning'; bytes32 public constant Manager = 'Manager'; bytes32 public constant TokenFactory = 'TokenFactory'; bytes32 public constant CreditLineController = 'CreditLineController'; bytes32 public constant CollateralWhitelist = 'CollateralWhitelist'; bytes32 public constant IdentifierWhitelist = 'IdentifierWhitelist'; bytes32 public constant LendingManager = 'LendingManager'; bytes32 public constant LendingStorageManager = 'LendingStorageManager'; bytes32 public constant CommissionReceiver = 'CommissionReceiver'; bytes32 public constant BuybackProgramReceiver = 'BuybackProgramReceiver'; bytes32 public constant LendingRewardsReceiver = 'LendingRewardsReceiver'; bytes32 public constant StakingRewardsReceiver = 'StakingRewardsReceiver'; bytes32 public constant JarvisToken = 'JarvisToken'; bytes32 public constant DebtTokenFactory = 'DebtTokenFactory'; bytes32 public constant VaultFactory = 'VaultFactory'; bytes32 public constant StakingLPVaultFactory = 'StakingLPVaultFactory'; bytes32 public constant PriceFeed = 'PriceFeed'; bytes32 public constant StakedJarvisToken = 'StakedJarvisToken'; bytes32 public constant StakingLPVaultData = 'StakingLPVaultData'; bytes32 public constant JarvisBrrrrr = 'JarvisBrrrrr'; bytes32 public constant MoneyMarketManager = 'MoneyMarketManager'; bytes32 public constant CrossChainBridge = 'CrossChainBridge'; bytes32 public constant TrustedForwarder = 'TrustedForwarder'; } library FactoryInterfaces { bytes32 public constant PoolFactory = 'PoolFactory'; bytes32 public constant SelfMintingFactory = 'SelfMintingFactory'; bytes32 public constant FixedRateFactory = 'FixedRateFactory'; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /** * @title Pool interface for making lending manager interacting with the pool */ interface ISynthereumLendingTransfer { /** * @notice Transfer a bearing amount to the lending manager * @notice Only the lending manager can call the function * @param _bearingAmount Amount of bearing token to transfer * @return bearingAmountOut Real bearing amount transferred to the lending manager */ function transferToLendingManager(uint256 _bearingAmount) external returns (uint256 bearingAmountOut); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ILendingStorageManager} from '../../../lending-module/interfaces/ILendingStorageManager.sol'; /** * @title Pool interface for claiming lending rewards */ interface ISynthereumLendingRewards { /** * @notice Claim rewards, associaated to the lending module supported by the pool * @notice Only the lending manager can call the function * @param _lendingInfo Address of lending module implementation and global args * @param _poolLendingStorage Addresses of collateral and bearing token of the pool * @param _recipient Address of recipient receiving rewards */ function claimLendingRewards( ILendingStorageManager.LendingInfo calldata _lendingInfo, ILendingStorageManager.PoolLendingStorage calldata _poolLendingStorage, address _recipient ) external; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; /** * @title PreciseUnitMath * @author Synthereum Protocol * * Arithmetic for fixed-point numbers with 18 decimals of precision. * */ library PreciseUnitMath { // The number One in precise units. uint256 internal constant PRECISE_UNIT = 10**18; // The number One in precise units multiplied for 10^18. uint256 internal constant DOUBLE_PRECISE_UNIT = 10**36; // Max unsigned integer value uint256 internal constant MAX_UINT_256 = type(uint256).max; /** * @dev Getter function since constants can't be read directly from libraries. */ function preciseUnit() internal pure returns (uint256) { return PRECISE_UNIT; } /** * @dev Getter function since constants can't be read directly from libraries. */ function maxUint256() internal pure returns (uint256) { return MAX_UINT_256; } /** * @dev Multiplies value a by value b (result is rounded down). It's assumed that the value b is the significand * of a number with 18 decimals precision. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return (a * b) / PRECISE_UNIT; } /** * @dev Multiplies value a by value b (result is rounded up). It's assumed that the value b is the significand * of a number with 18 decimals precision. */ function mulCeil(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0 || b == 0) { return 0; } return (((a * b) - 1) / PRECISE_UNIT) + 1; } /** * @dev Divides value a by value b (result is rounded down). */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return (a * PRECISE_UNIT) / b; } /** * @dev Divides value a by value b (result is rounded up or away from 0). */ function divCeil(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, 'Cant divide by 0'); return a > 0 ? (((a * PRECISE_UNIT) - 1) / b) + 1 : 0; } /** * @dev Performs the power on a specified value, reverts on overflow. */ function safePower(uint256 a, uint256 pow) internal pure returns (uint256) { require(a > 0, 'Value must be positive'); uint256 result = 1; for (uint256 i = 0; i < pow; i++) { uint256 previousResult = result; result = previousResult * a; } return result; } /** * @dev The minimum of `a` and `b`. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev The maximum of `a` and `b`. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.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 IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ 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' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @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. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {ISynthereumFinder} from '../../core/interfaces/IFinder.sol'; import {ISynthereumFactoryVersioning} from '../../core/interfaces/IFactoryVersioning.sol'; import {SynthereumInterfaces, FactoryInterfaces} from '../../core/Constants.sol'; /** @title Library to use for controlling the access of a functions from the factories */ library SynthereumFactoryAccess { /** *@notice Revert if caller is not a Pool factory * @param _finder Synthereum finder */ function _onlyPoolFactory(ISynthereumFinder _finder) internal view { ISynthereumFactoryVersioning factoryVersioning = ISynthereumFactoryVersioning( _finder.getImplementationAddress(SynthereumInterfaces.FactoryVersioning) ); uint8 numberOfPoolFactories = factoryVersioning.numberOfFactoryVersions( FactoryInterfaces.PoolFactory ); require( _checkSenderIsFactory( factoryVersioning, numberOfPoolFactories, FactoryInterfaces.PoolFactory ), 'Not allowed' ); } /** * @notice Revert if caller is not a Pool factory or a Fixed rate factory * @param _finder Synthereum finder */ function _onlyPoolFactoryOrFixedRateFactory(ISynthereumFinder _finder) internal view { ISynthereumFactoryVersioning factoryVersioning = ISynthereumFactoryVersioning( _finder.getImplementationAddress(SynthereumInterfaces.FactoryVersioning) ); uint8 numberOfPoolFactories = factoryVersioning.numberOfFactoryVersions( FactoryInterfaces.PoolFactory ); uint8 numberOfFixedRateFactories = factoryVersioning .numberOfFactoryVersions(FactoryInterfaces.FixedRateFactory); bool isPoolFactory = _checkSenderIsFactory( factoryVersioning, numberOfPoolFactories, FactoryInterfaces.PoolFactory ); if (isPoolFactory) { return; } bool isFixedRateFactory = _checkSenderIsFactory( factoryVersioning, numberOfFixedRateFactories, FactoryInterfaces.FixedRateFactory ); if (isFixedRateFactory) { return; } revert('Sender must be a Pool or FixedRate factory'); } /** * @notice Check if sender is a factory * @param _factoryVersioning SynthereumFactoryVersioning contract * @param _numberOfFactories Total number of versions of a factory type * @param _factoryKind Type of the factory * @return isFactory True if sender is a factory, otherwise false */ function _checkSenderIsFactory( ISynthereumFactoryVersioning _factoryVersioning, uint8 _numberOfFactories, bytes32 _factoryKind ) private view returns (bool isFactory) { uint8 counterFactory; for (uint8 i = 0; counterFactory < _numberOfFactories; i++) { try _factoryVersioning.getFactoryVersion(_factoryKind, i) returns ( address factory ) { if (msg.sender == factory) { isFactory = true; break; } else { counterFactory++; if (counterFactory == _numberOfFactories) { isFactory = false; } } } catch {} } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /** * @title Provides addresses of different versions of pools factory and derivative factory */ interface ISynthereumFactoryVersioning { /** @notice Sets a Factory * @param factoryType Type of factory * @param version Version of the factory to be set * @param factory The pool factory address to be set */ function setFactory( bytes32 factoryType, uint8 version, address factory ) external; /** @notice Removes a factory * @param factoryType The type of factory to be removed * @param version Version of the factory to be removed */ function removeFactory(bytes32 factoryType, uint8 version) external; /** @notice Gets a factory contract address * @param factoryType The type of factory to be checked * @param version Version of the factory to be checked * @return factory Address of the factory contract */ function getFactoryVersion(bytes32 factoryType, uint8 version) external view returns (address factory); /** @notice Gets the number of factory versions for a specific type * @param factoryType The type of factory to be checked * @return numberOfVersions Total number of versions for a specific factory */ function numberOfFactoryVersions(bytes32 factoryType) external view returns (uint8 numberOfVersions); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {ISynthereumFinder} from '../core/interfaces/IFinder.sol'; import {ISynthereumFactoryVersioning} from '../core/interfaces/IFactoryVersioning.sol'; import {ILendingStorageManager} from './interfaces/ILendingStorageManager.sol'; import {ILendingModule} from './interfaces/ILendingModule.sol'; import {SynthereumInterfaces, FactoryInterfaces} from '../core/Constants.sol'; import {PreciseUnitMath} from '../base/utils/PreciseUnitMath.sol'; import {SynthereumFactoryAccess} from '../common/libs/FactoryAccess.sol'; import {EnumerableSet} from '../../@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; import {ReentrancyGuard} from '../../@openzeppelin/contracts/security/ReentrancyGuard.sol'; contract LendingStorageManager is ILendingStorageManager, ReentrancyGuard { using EnumerableSet for EnumerableSet.AddressSet; mapping(bytes32 => LendingInfo) internal idToLendingInfo; EnumerableSet.AddressSet internal swapModules; mapping(address => address) internal collateralToSwapModule; // ie USDC -> JRTSwapUniswap address mapping(address => PoolStorage) internal poolStorage; // ie jEUR/USDC pooldata ISynthereumFinder immutable synthereumFinder; modifier onlyLendingManager() { require( msg.sender == synthereumFinder.getImplementationAddress( SynthereumInterfaces.LendingManager ), 'Not allowed' ); _; } modifier onlyPoolFactory() { SynthereumFactoryAccess._onlyPoolFactory(synthereumFinder); _; } constructor(ISynthereumFinder _finder) { synthereumFinder = _finder; } function setLendingModule( string calldata _id, LendingInfo calldata _lendingInfo ) external override nonReentrant onlyLendingManager { bytes32 lendingId = keccak256(abi.encode(_id)); require(lendingId != 0x00, 'Wrong module identifier'); idToLendingInfo[lendingId] = _lendingInfo; } function addSwapProtocol(address _swapModule) external override nonReentrant onlyLendingManager { require(_swapModule != address(0), 'Swap module can not be 0x'); require(swapModules.add(_swapModule), 'Swap module already supported'); } function removeSwapProtocol(address _swapModule) external override nonReentrant onlyLendingManager { require(_swapModule != address(0), 'Swap module can not be 0x'); require(swapModules.remove(_swapModule), 'Swap module not supported'); } function setSwapModule(address _collateral, address _swapModule) external override nonReentrant onlyLendingManager { require( swapModules.contains(_swapModule) || _swapModule == address(0), 'Swap module not supported' ); collateralToSwapModule[_collateral] = _swapModule; } function setShares( address _pool, uint64 _daoInterestShare, uint64 _jrtBuybackShare ) external override nonReentrant onlyLendingManager { PoolStorage storage poolData = poolStorage[_pool]; require(poolData.lendingModuleId != 0x00, 'Bad pool'); require( _jrtBuybackShare <= PreciseUnitMath.PRECISE_UNIT && _daoInterestShare <= PreciseUnitMath.PRECISE_UNIT, 'Invalid share' ); poolData.jrtBuybackShare = _jrtBuybackShare; poolData.daoInterestShare = _daoInterestShare; } function setPoolStorage( string calldata _lendingID, address _pool, address _collateral, address _interestBearingToken, uint64 _daoInterestShare, uint64 _jrtBuybackShare ) external override nonReentrant onlyPoolFactory { bytes32 id = keccak256(abi.encode(_lendingID)); LendingInfo memory lendingInfo = idToLendingInfo[id]; address lendingModule = lendingInfo.lendingModule; require(lendingModule != address(0), 'Module not supported'); require( _jrtBuybackShare <= PreciseUnitMath.PRECISE_UNIT && _daoInterestShare <= PreciseUnitMath.PRECISE_UNIT, 'Invalid share' ); // set pool storage PoolStorage storage poolData = poolStorage[_pool]; require(poolData.lendingModuleId == 0x00, 'Pool already exists'); poolData.lendingModuleId = id; poolData.collateral = _collateral; poolData.jrtBuybackShare = _jrtBuybackShare; poolData.daoInterestShare = _daoInterestShare; // set interest bearing token _setBearingToken( poolData, _collateral, lendingModule, lendingInfo, _interestBearingToken ); } function migratePoolStorage( address _oldPool, address _newPool, uint256 _newCollateralDeposited ) external override nonReentrant onlyLendingManager { PoolStorage memory oldPoolData = poolStorage[_oldPool]; bytes32 oldLendingId = oldPoolData.lendingModuleId; require(oldLendingId != 0x00, 'Bad migration pool'); PoolStorage storage newPoolData = poolStorage[_newPool]; require(newPoolData.lendingModuleId == 0x00, 'Bad new pool'); // copy storage to new pool newPoolData.lendingModuleId = oldLendingId; newPoolData.collateral = oldPoolData.collateral; newPoolData.interestBearingToken = oldPoolData.interestBearingToken; newPoolData.jrtBuybackShare = oldPoolData.jrtBuybackShare; newPoolData.daoInterestShare = oldPoolData.daoInterestShare; newPoolData.collateralDeposited = _newCollateralDeposited; newPoolData.unclaimedDaoJRT = oldPoolData.unclaimedDaoJRT; newPoolData.unclaimedDaoCommission = oldPoolData.unclaimedDaoCommission; // delete old pool slot delete poolStorage[_oldPool]; } function migrateLendingModule( string calldata _newLendingID, address _pool, address _newInterestBearingToken ) external override nonReentrant onlyLendingManager returns (PoolStorage memory, LendingInfo memory) { bytes32 id = keccak256(abi.encode(_newLendingID)); LendingInfo memory newLendingInfo = idToLendingInfo[id]; address newLendingModule = newLendingInfo.lendingModule; require(newLendingModule != address(0), 'Id not existent'); // set lending module PoolStorage storage poolData = poolStorage[_pool]; poolData.lendingModuleId = id; // set interest bearing token _setBearingToken( poolData, poolData.collateral, newLendingModule, newLendingInfo, _newInterestBearingToken ); return (poolData, newLendingInfo); } function updateValues( address _pool, uint256 _collateralDeposited, uint256 _daoJRT, uint256 _daoInterest ) external override nonReentrant onlyLendingManager { PoolStorage storage poolData = poolStorage[_pool]; require(poolData.lendingModuleId != 0x00, 'Bad pool'); // update collateral deposit amount of the pool poolData.collateralDeposited = _collateralDeposited; // update dao unclaimed interest of the pool poolData.unclaimedDaoJRT = _daoJRT; poolData.unclaimedDaoCommission = _daoInterest; } function getLendingModule(string calldata _id) external view override returns (LendingInfo memory lendingInfo) { bytes32 lendingId = keccak256(abi.encode(_id)); require(lendingId != 0x00, 'Wrong module identifier'); lendingInfo = idToLendingInfo[lendingId]; require( lendingInfo.lendingModule != address(0), 'Lending module not supported' ); } function getPoolData(address _pool) external view override returns (PoolStorage memory poolData, LendingInfo memory lendingInfo) { poolData = poolStorage[_pool]; require(poolData.lendingModuleId != 0x00, 'Not existing pool'); lendingInfo = idToLendingInfo[poolData.lendingModuleId]; } function getPoolStorage(address _pool) external view override returns (PoolStorage memory poolData) { poolData = poolStorage[_pool]; require(poolData.lendingModuleId != 0x00, 'Not existing pool'); } function getLendingData(address _pool) external view override returns ( PoolLendingStorage memory lendingStorage, LendingInfo memory lendingInfo ) { PoolStorage storage poolData = poolStorage[_pool]; require(poolData.lendingModuleId != 0x00, 'Not existing pool'); lendingStorage.collateralToken = poolData.collateral; lendingStorage.interestToken = poolData.interestBearingToken; lendingInfo = idToLendingInfo[poolData.lendingModuleId]; } function getSwapModules() external view override returns (address[] memory) { uint256 numberOfModules = swapModules.length(); address[] memory modulesList = new address[](numberOfModules); for (uint256 j = 0; j < numberOfModules; j++) { modulesList[j] = swapModules.at(j); } return modulesList; } function getCollateralSwapModule(address _collateral) external view override returns (address swapModule) { swapModule = collateralToSwapModule[_collateral]; require( swapModule != address(0), 'Swap module not added for this collateral' ); require(swapModules.contains(swapModule), 'Swap module not supported'); } function getInterestBearingToken(address _pool) external view override returns (address interestTokenAddr) { require(poolStorage[_pool].lendingModuleId != 0x00, 'Not existing pool'); interestTokenAddr = poolStorage[_pool].interestBearingToken; } function getShares(address _pool) external view override returns (uint256 jrtBuybackShare, uint256 daoInterestShare) { require(poolStorage[_pool].lendingModuleId != 0x00, 'Not existing pool'); jrtBuybackShare = poolStorage[_pool].jrtBuybackShare; daoInterestShare = poolStorage[_pool].daoInterestShare; } function getCollateralDeposited(address _pool) external view override returns (uint256 collateralAmount) { require(poolStorage[_pool].lendingModuleId != 0x00, 'Not existing pool'); collateralAmount = poolStorage[_pool].collateralDeposited; } function _setBearingToken( PoolStorage storage _actualPoolData, address _collateral, address _lendingModule, LendingInfo memory _lendingInfo, address _interestToken ) internal { try ILendingModule(_lendingModule).getInterestBearingToken( _collateral, _lendingInfo.args ) returns (address interestTokenAddr) { _actualPoolData.interestBearingToken = interestTokenAddr; } catch { require(_interestToken != address(0), 'No bearing token passed'); _actualPoolData.interestBearingToken = _interestToken; } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {ISynthereumFinder} from '../../../core/interfaces/IFinder.sol'; import {SynthereumFactoryAccess} from '../../../common/libs/FactoryAccess.sol'; /** * @title Abstract contract inherited by pools for moving storage from one pool to another */ contract SynthereumPoolMigration { ISynthereumFinder internal finder; modifier onlyPoolFactory() { SynthereumFactoryAccess._onlyPoolFactory(finder); _; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {ISynthereumFinder} from '../../../core/interfaces/IFinder.sol'; import {SynthereumPoolMigration} from './PoolMigration.sol'; /** * @title Abstract contract inherit by pools for moving storage from one pool to another */ abstract contract SynthereumPoolMigrationFrom is SynthereumPoolMigration { /** * @notice Migrate storage from this pool resetting and cleaning data * @notice This can be called only by a pool factory * @return poolVersion Version of the pool * @return price Actual price of the pair * @return storageBytes Pool storage encoded in bytes */ function migrateStorage() external virtual onlyPoolFactory returns ( uint8 poolVersion, uint256 price, bytes memory storageBytes ) { _modifyStorageFrom(); (poolVersion, price, storageBytes) = _encodeStorage(); _cleanStorage(); } /** * @notice Transfer all bearing tokens to another address * @notice Only the lending manager can call the function * @param _recipient Address receving bearing amount * @return migrationAmount Total balance of the pool in bearing tokens before migration */ function migrateTotalFunds(address _recipient) external virtual returns (uint256 migrationAmount); /** * @notice Function to implement for modifying storage before the encoding */ function _modifyStorageFrom() internal virtual; /** * @notice Function to implement for cleaning and resetting the storage to the initial state */ function _cleanStorage() internal virtual; /** * @notice Function to implement for encoding storage in bytes * @return poolVersion Version of the pool * @return price Actual price of the pair * @return storageBytes Pool storage encoded in bytes */ function _encodeStorage() internal view virtual returns ( uint8 poolVersion, uint256 price, bytes memory storageBytes ); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {ILendingModule} from '../interfaces/ILendingModule.sol'; import {ILendingStorageManager} from '../interfaces/ILendingStorageManager.sol'; import {SafeERC20} from '../../../@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import {SynthereumPoolMigrationFrom} from '../../synthereum-pool/common/migration/PoolMigrationFrom.sol'; // this module serves as a mock module // it can be attached to any pool in order to avoid using a lending protocol contract TransparentModule is ILendingModule { using SafeERC20 for IERC20; function deposit( ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata, uint256 _amount ) external override returns ( uint256 totalInterest, uint256 tokensOut, uint256 tokensTransferred ) { // transfer back collateral to the pool (msg.sender) IERC20 collateral = IERC20(_poolData.collateral); require(collateral.balanceOf(address(this)) >= _amount, 'Wrong balance'); tokensTransferred = _amount; tokensOut = tokensTransferred; collateral.safeTransfer(msg.sender, tokensTransferred); } function withdraw( ILendingStorageManager.PoolStorage calldata _poolData, address, bytes calldata, uint256 _amount, address _recipient ) external override returns ( uint256 totalInterest, uint256 tokensOut, uint256 tokensTransferred ) { // proxy should have received interest tokens (same as collateral in this case) from the pool tokensTransferred = _amount; tokensOut = tokensTransferred; // transfer collateral to recipient IERC20(_poolData.interestBearingToken).safeTransfer( _recipient, tokensTransferred ); } function totalTransfer( address _oldPool, address _newPool, address, address, bytes calldata ) external returns (uint256 prevTotalCollateral, uint256 actualTotalCollateral) { prevTotalCollateral = SynthereumPoolMigrationFrom(_oldPool) .migrateTotalFunds(_newPool); actualTotalCollateral = prevTotalCollateral; } function claimRewards( bytes calldata, address, address, address ) external pure override { revert('Claim rewards not supported'); } function getUpdatedInterest( address, ILendingStorageManager.PoolStorage calldata, bytes calldata ) external pure override returns (uint256 totalInterest) {} function getAccumulatedInterest( address, ILendingStorageManager.PoolStorage calldata, bytes calldata ) external pure override returns (uint256 totalInterest) {} function getInterestBearingToken(address _collateral, bytes calldata) external pure override returns (address token) { token = _collateral; } function collateralToInterestToken( uint256 _collateralAmount, address, address, bytes calldata ) external pure override returns (uint256 interestTokenAmount) { interestTokenAmount = _collateralAmount; } function interestTokenToCollateral( uint256 _interestTokenAmount, address, address, bytes calldata ) external pure override returns (uint256 collateralAmount) { collateralAmount = _interestTokenAmount; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {Address} from '../../../@openzeppelin/contracts/utils/Address.sol'; import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {SafeERC20} from '../../../@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import {IJRTSwapModule} from '../interfaces/IJrtSwapModule.sol'; import {IUniswapV2Router02} from '../../../@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol'; contract UniV2JRTSwapModule is IJRTSwapModule { using SafeERC20 for IERC20; struct SwapInfo { address routerAddress; address[] tokenSwapPath; uint256 expiration; uint256 minTokensOut; } function swapToJRT( address _recipient, address _collateral, address _jarvisToken, uint256 _amountIn, bytes calldata _params ) external override returns (uint256 amountOut) { // decode swapInfo SwapInfo memory swapInfo = abi.decode(_params, (SwapInfo)); uint256 pathLength = swapInfo.tokenSwapPath.length; require( swapInfo.tokenSwapPath[pathLength - 1] == _jarvisToken, 'Wrong token swap path' ); // swap to JRT to final recipient IUniswapV2Router02 router = IUniswapV2Router02(swapInfo.routerAddress); IERC20(_collateral).safeIncreaseAllowance(address(router), _amountIn); amountOut = router.swapExactTokensForTokens( _amountIn, swapInfo.minTokensOut, swapInfo.tokenSwapPath, _recipient, swapInfo.expiration )[pathLength - 1]; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; interface IJRTSwapModule { /** * @notice executes an AMM swap from collateral to JRT * @param _recipient address receiving JRT tokens * @param _collateral address of the collateral token to swap * @param _jarvisToken address of the jarvis token to buy * @param _amountIn exact amount of collateral to swap * @param _params extra params needed on the specific implementation (with different AMM) * @return amountOut amount of JRT in output */ function swapToJRT( address _recipient, address _collateral, address _jarvisToken, uint256 _amountIn, bytes calldata _params ) external returns (uint256 amountOut); }
pragma solidity >=0.6.2; import './IUniswapV2Router01.sol'; interface IUniswapV2Router02 is IUniswapV2Router01 { function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; }
pragma solidity >=0.6.2; interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {Address} from '../../../@openzeppelin/contracts/utils/Address.sol'; import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {SafeERC20} from '../../../@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import {ISynthereumDeployment} from '../../common/interfaces/IDeployment.sol'; import {IBalancerVault} from '../interfaces/IBalancerVault.sol'; import {IJRTSwapModule} from '../interfaces/IJrtSwapModule.sol'; contract BalancerJRTSwapModule is IJRTSwapModule { using SafeERC20 for IERC20; struct SwapInfo { bytes32 poolId; address routerAddress; uint256 minTokensOut; // anti slippage uint256 expiration; } function swapToJRT( address _recipient, address _collateral, address _jarvisToken, uint256 _amountIn, bytes calldata _params ) external override returns (uint256 amountOut) { // decode swapInfo SwapInfo memory swapInfo = abi.decode(_params, (SwapInfo)); // build params IBalancerVault.SingleSwap memory singleSwap = IBalancerVault.SingleSwap( swapInfo.poolId, IBalancerVault.SwapKind.GIVEN_IN, _collateral, _jarvisToken, _amountIn, '0x00' ); IBalancerVault.FundManagement memory funds = IBalancerVault.FundManagement( address(this), false, payable(_recipient), false ); // swap to JRT to final recipient IBalancerVault router = IBalancerVault(swapInfo.routerAddress); IERC20(_collateral).safeIncreaseAllowance(address(router), _amountIn); amountOut = router.swap( singleSwap, funds, swapInfo.minTokensOut, swapInfo.expiration ); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {ISynthereumFinder} from '../../core/interfaces/IFinder.sol'; /** * @title Interface that a pool MUST have in order to be included in the deployer */ interface ISynthereumDeployment { /** * @notice Get Synthereum finder of the pool/self-minting derivative * @return finder Returns finder contract */ function synthereumFinder() external view returns (ISynthereumFinder finder); /** * @notice Get Synthereum version * @return contractVersion Returns the version of this pool/self-minting derivative */ function version() external view returns (uint8 contractVersion); /** * @notice Get the collateral token of this pool/self-minting derivative * @return collateralCurrency The ERC20 collateral token */ function collateralToken() external view returns (IERC20 collateralCurrency); /** * @notice Get the synthetic token associated to this pool/self-minting derivative * @return syntheticCurrency The ERC20 synthetic token */ function syntheticToken() external view returns (IERC20 syntheticCurrency); /** * @notice Get the synthetic token symbol associated to this pool/self-minting derivative * @return symbol The ERC20 synthetic token symbol */ function syntheticTokenSymbol() external view returns (string memory symbol); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; interface IBalancerVault { 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); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {ILendingModule} from '../interfaces/ILendingModule.sol'; import {ILendingStorageManager} from '../interfaces/ILendingStorageManager.sol'; import {ICompoundToken, IComptroller} from '../interfaces/ICToken.sol'; import {ExponentialNoError} from '../libs/ExponentialNoError.sol'; import {IRewardsController} from '../interfaces/IRewardsController.sol'; import {Address} from '../../../@openzeppelin/contracts/utils/Address.sol'; import {SafeERC20} from '../../../@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import {PreciseUnitMath} from '../../base/utils/PreciseUnitMath.sol'; import {SynthereumPoolMigrationFrom} from '../../synthereum-pool/common/migration/PoolMigrationFrom.sol'; contract CompoundModule is ILendingModule, ExponentialNoError { using SafeERC20 for IERC20; using SafeERC20 for ICompoundToken; function deposit( ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata, uint256 _amount ) external override returns ( uint256 totalInterest, uint256 tokensOut, uint256 tokensTransferred ) { // proxy should have received collateral from the pool IERC20 collateral = IERC20(_poolData.collateral); require(collateral.balanceOf(address(this)) >= _amount, 'Wrong balance'); // initialise compound interest token ICompoundToken cToken = ICompoundToken(_poolData.interestBearingToken); // get tokens balance before uint256 cTokenBalanceBefore = cToken.balanceOf(address(this)); uint256 totalPrevDeposit; // calculate accrued interest since last operation (totalInterest, totalPrevDeposit) = calculateGeneratedInterest( msg.sender, _poolData, 0, cToken, true ); // approve and deposit underlying collateral.safeIncreaseAllowance(address(cToken), _amount); require(cToken.mint(_amount) == 0, 'Failed mint'); uint256 cTokenBalanceAfter = cToken.balanceOf(address(this)); // set return values tokensTransferred = cTokenBalanceAfter - cTokenBalanceBefore; // transfer cToken to pool cToken.transfer(msg.sender, tokensTransferred); tokensOut = cToken.balanceOfUnderlying(msg.sender) - totalPrevDeposit - totalInterest; } function withdraw( ILendingStorageManager.PoolStorage calldata _poolData, address _pool, bytes calldata, uint256 _cTokenAmount, address _recipient ) external override returns ( uint256 totalInterest, uint256 tokensOut, uint256 tokensTransferred ) { // initialise compound interest token ICompoundToken cToken = ICompoundToken(_poolData.interestBearingToken); IERC20 collateralToken = IERC20(_poolData.collateral); uint256 totalPrevDeposit; // calculate accrued interest since last operation (totalInterest, totalPrevDeposit) = calculateGeneratedInterest( _pool, _poolData, _cTokenAmount, cToken, false ); // get balances before redeeming uint256 collBalanceBefore = collateralToken.balanceOf(address(this)); // redeem require(cToken.redeem(_cTokenAmount) == 0, 'Failed withdraw'); // get balances after redeeming uint256 collBalanceAfter = collateralToken.balanceOf(address(this)); // set return values tokensOut = totalPrevDeposit + totalInterest - cToken.balanceOfUnderlying(_pool); tokensTransferred = collBalanceAfter - collBalanceBefore; // transfer underlying collateralToken.safeTransfer(_recipient, tokensTransferred); } function totalTransfer( address _oldPool, address _newPool, address, address _interestToken, bytes calldata ) external override returns (uint256 prevTotalCollateral, uint256 actualTotalCollateral) { uint256 prevTotalcTokens = SynthereumPoolMigrationFrom(_oldPool) .migrateTotalFunds(_newPool); Exp memory exchangeRate = Exp({ mantissa: ICompoundToken(_interestToken).exchangeRateCurrent() }); prevTotalCollateral = mul_ScalarTruncate(exchangeRate, prevTotalcTokens); actualTotalCollateral = ICompoundToken(_interestToken).balanceOfUnderlying( _newPool ); } function claimRewards( bytes calldata, address, address, address ) external override { revert('Claim rewards not supported'); } function getUpdatedInterest( address _poolAddress, ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata ) external override returns (uint256 totalInterest) { // instantiate cToken ICompoundToken cToken = ICompoundToken(_poolData.interestBearingToken); // calculate collateral uint256 totCollateral = cToken.balanceOfUnderlying(_poolAddress); totalInterest = totCollateral - _poolData.collateralDeposited - _poolData.unclaimedDaoCommission - _poolData.unclaimedDaoJRT; } function getAccumulatedInterest( address _poolAddress, ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata ) external view override returns (uint256 totalInterest) { ICompoundToken cToken = ICompoundToken(_poolData.interestBearingToken); (, uint256 tokenBalance, , uint256 excMantissa) = cToken.getAccountSnapshot( _poolAddress ); Exp memory exchangeRate = Exp({mantissa: excMantissa}); uint256 totCollateral = mul_ScalarTruncate(exchangeRate, tokenBalance); totalInterest = totCollateral - _poolData.collateralDeposited - _poolData.unclaimedDaoCommission - _poolData.unclaimedDaoJRT; } function getInterestBearingToken( address _collateral, bytes calldata _extraArgs ) external view override returns (address token) { IComptroller comptroller = IComptroller(abi.decode(_extraArgs, (address))); address[] memory markets = comptroller.getAllMarkets(); for (uint256 i = 0; i < markets.length; i++) { try ICompoundToken(markets[i]).underlying() returns (address coll) { if (coll == _collateral) { token = markets[i]; break; } } catch {} } require(token != address(0), 'Token not found'); } function collateralToInterestToken( uint256 _collateralAmount, address, address _interestToken, bytes calldata ) external view override returns (uint256 interestTokenAmount) { uint256 excMantissa = ICompoundToken(_interestToken).exchangeRateStored(); Exp memory exchangeRate = Exp({mantissa: excMantissa}); return div_(_collateralAmount, exchangeRate); } function interestTokenToCollateral( uint256 _interestTokenAmount, address, address _interestToken, bytes calldata ) external view override returns (uint256 collateralAmount) { uint256 excMantissa = ICompoundToken(_interestToken).exchangeRateStored(); Exp memory exchangeRate = Exp({mantissa: excMantissa}); return mul_ScalarTruncate(exchangeRate, _interestTokenAmount); } function calculateGeneratedInterest( address _poolAddress, ILendingStorageManager.PoolStorage calldata _pool, uint256 _cTokenAmount, ICompoundToken _cToken, bool _isDeposit ) internal returns (uint256 totalInterestGenerated, uint256 totalPrevDeposit) { // get cToken pool balance and rate Exp memory exchangeRate = Exp({mantissa: _cToken.exchangeRateCurrent()}); uint256 cTokenBalancePool = _cToken.balanceOf(_poolAddress); // determine amount of collateral the pool had before this operation uint256 poolBalance = mul_ScalarTruncate( exchangeRate, _isDeposit ? cTokenBalancePool : cTokenBalancePool + _cTokenAmount ); totalPrevDeposit = _pool.collateralDeposited + _pool.unclaimedDaoCommission + _pool.unclaimedDaoJRT; totalInterestGenerated = poolBalance - totalPrevDeposit; } }
// SPDX-License-Identifier: AGPL-3.0-only import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol'; pragma solidity ^0.8.9; interface ICompoundToken is IERC20 { function mint(uint256) external returns (uint256); function borrow(uint256) external returns (uint256); function borrowBalanceCurrent(address account) external returns (uint256); function repayBorrow(uint256) external returns (uint256); function exchangeRateCurrent() external returns (uint256); function supplyRatePerBlock() external returns (uint256); function redeem(uint256) external returns (uint256); function redeemUnderlying(uint256) external returns (uint256); function balanceOfUnderlying(address owner) external returns (uint256); function getAccountSnapshot(address account) external view returns ( uint256, uint256, uint256, uint256 ); function underlying() external view returns (address); function getOwner() external view returns (address); function exchangeRateStored() external view returns (uint256); } interface IComptroller { function getAllMarkets() external view returns (address[] memory); }
// SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.9; /** * @title Exponential module for storing fixed-precision decimals * @author Compound * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: * `Exp({mantissa: 5100000000000000000})`. */ contract ExponentialNoError { uint256 constant expScale = 1e18; uint256 constant doubleScale = 1e36; uint256 constant halfExpScale = expScale / 2; uint256 constant mantissaOne = expScale; struct Exp { uint256 mantissa; } struct Double { uint256 mantissa; } /** * @dev Truncates the given exp to a whole number value. * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 */ function truncate(Exp memory exp) internal pure returns (uint256) { // Note: We are not using careful math here as we're performing a division that cannot fail return exp.mantissa / expScale; } /** * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. */ function mul_ScalarTruncate(Exp memory a, uint256 scalar) internal pure returns (uint256) { Exp memory product = mul_(a, scalar); return truncate(product); } /** * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. */ function mul_ScalarTruncateAddUInt( Exp memory a, uint256 scalar, uint256 addend ) internal pure returns (uint256) { Exp memory product = mul_(a, scalar); return add_(truncate(product), addend); } /** * @dev Checks if first Exp is less than second Exp. */ function lessThanExp(Exp memory left, Exp memory right) internal pure returns (bool) { return left.mantissa < right.mantissa; } /** * @dev Checks if left Exp <= right Exp. */ function lessThanOrEqualExp(Exp memory left, Exp memory right) internal pure returns (bool) { return left.mantissa <= right.mantissa; } /** * @dev Checks if left Exp > right Exp. */ function greaterThanExp(Exp memory left, Exp memory right) internal pure returns (bool) { return left.mantissa > right.mantissa; } /** * @dev returns true if Exp is exactly zero */ function isZeroExp(Exp memory value) internal pure returns (bool) { return value.mantissa == 0; } function safe224(uint256 n, string memory errorMessage) internal pure returns (uint224) { require(n < 2**224, errorMessage); return uint224(n); } function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function add_(Exp memory a, Exp memory b) internal pure returns (Exp memory) { return Exp({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(Double memory a, Double memory b) internal pure returns (Double memory) { return Double({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } function sub_(Exp memory a, Exp memory b) internal pure returns (Exp memory) { return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(Double memory a, Double memory b) internal pure returns (Double memory) { return Double({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } function mul_(Exp memory a, Exp memory b) internal pure returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); } function mul_(Exp memory a, uint256 b) internal pure returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b)}); } function mul_(uint256 a, Exp memory b) internal pure returns (uint256) { return mul_(a, b.mantissa) / expScale; } function mul_(Double memory a, Double memory b) internal pure returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); } function mul_(Double memory a, uint256 b) internal pure returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b)}); } function mul_(uint256 a, Double memory b) internal pure returns (uint256) { return mul_(a, b.mantissa) / doubleScale; } function mul_(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } function div_(Exp memory a, Exp memory b) internal pure returns (Exp memory) { return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); } function div_(Exp memory a, uint256 b) internal pure returns (Exp memory) { return Exp({mantissa: div_(a.mantissa, b)}); } function div_(uint256 a, Exp memory b) internal pure returns (uint256) { return div_(mul_(a, expScale), b.mantissa); } function div_(Double memory a, Double memory b) internal pure returns (Double memory) { return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); } function div_(Double memory a, uint256 b) internal pure returns (Double memory) { return Double({mantissa: div_(a.mantissa, b)}); } function div_(uint256 a, Double memory b) internal pure returns (uint256) { return div_(mul_(a, doubleScale), b.mantissa); } function div_(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } function fraction(uint256 a, uint256 b) internal pure returns (Double memory) { return Double({mantissa: div_(mul_(a, doubleScale), b)}); } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity >0.8.0; /** * @title IRewardsController * @author Aave * @notice Defines the basic interface for a Rewards Controller. */ interface IRewardsController { /** * @dev Claims all rewards for a user to the desired address, on all the assets of the pool, accumulating the pending rewards * @param assets The list of assets to check eligible distributions before claiming rewards * @param to The address that will be receiving the rewards * @return rewardsList List of addresses of the reward tokens * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardList" **/ function claimAllRewards(address[] calldata assets, address to) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {IERC20} from '../../../@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {ILendingModule} from '../interfaces/ILendingModule.sol'; import {ILendingStorageManager} from '../interfaces/ILendingStorageManager.sol'; import {IPool} from '../interfaces/IAaveV3.sol'; import {IRewardsController} from '../interfaces/IRewardsController.sol'; import {Address} from '../../../@openzeppelin/contracts/utils/Address.sol'; import {SafeERC20} from '../../../@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import {PreciseUnitMath} from '../../base/utils/PreciseUnitMath.sol'; import {SynthereumPoolMigrationFrom} from '../../synthereum-pool/common/migration/PoolMigrationFrom.sol'; contract AaveV3Module is ILendingModule { using SafeERC20 for IERC20; function deposit( ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata _lendingArgs, uint256 _amount ) external override returns ( uint256 totalInterest, uint256 tokensOut, uint256 tokensTransferred ) { // calculate accrued interest since last operation (uint256 interest, uint256 poolBalance) = calculateGeneratedInterest( msg.sender, _poolData, _amount, true ); // proxy should have received collateral from the pool IERC20 collateral = IERC20(_poolData.collateral); require(collateral.balanceOf(address(this)) >= _amount, 'Wrong balance'); // aave deposit - approve (address moneyMarket, ) = abi.decode(_lendingArgs, (address, address)); collateral.safeIncreaseAllowance(moneyMarket, _amount); IPool(moneyMarket).supply( address(collateral), _amount, msg.sender, uint16(0) ); // aave tokens are usually 1:1 (but in some case there is dust-wei of rounding) uint256 netDeposit = IERC20(_poolData.interestBearingToken).balanceOf( msg.sender ) - poolBalance; totalInterest = interest; tokensOut = netDeposit; tokensTransferred = netDeposit; } function withdraw( ILendingStorageManager.PoolStorage calldata _poolData, address _pool, bytes calldata _lendingArgs, uint256 _aTokensAmount, address _recipient ) external override returns ( uint256 totalInterest, uint256 tokensOut, uint256 tokensTransferred ) { // proxy should have received interest tokens from the pool IERC20 interestToken = IERC20(_poolData.interestBearingToken); uint256 withdrawAmount = PreciseUnitMath.min( interestToken.balanceOf(address(this)), _aTokensAmount + 1 ); // calculate accrued interest since last operation (totalInterest, ) = calculateGeneratedInterest( _pool, _poolData, _aTokensAmount, false ); uint256 initialBalance = IERC20(_poolData.collateral).balanceOf(_recipient); // aave withdraw - approve (address moneyMarket, ) = abi.decode(_lendingArgs, (address, address)); interestToken.safeIncreaseAllowance(moneyMarket, withdrawAmount); IPool(moneyMarket).withdraw( _poolData.collateral, withdrawAmount, _recipient ); // aave tokens are usually 1:1 (but in some case there is dust-wei of rounding) uint256 netWithdrawal = IERC20(_poolData.collateral).balanceOf(_recipient) - initialBalance; tokensOut = _aTokensAmount; tokensTransferred = netWithdrawal; } function totalTransfer( address _oldPool, address _newPool, address, address _interestToken, bytes calldata ) external returns (uint256 prevTotalCollateral, uint256 actualTotalCollateral) { prevTotalCollateral = SynthereumPoolMigrationFrom(_oldPool) .migrateTotalFunds(_newPool); actualTotalCollateral = IERC20(_interestToken).balanceOf(_newPool); } /** * @notice Claim the rewards associated to the bearing tokens of the caller(pool) * @param _lendingArgs encoded args needed by the specific implementation * @param _bearingToken Address of the bearing token of the pool * @param _recipient address to which send rewards */ function claimRewards( bytes calldata _lendingArgs, address, address _bearingToken, address _recipient ) external override { (, address rewardsController) = abi.decode( _lendingArgs, (address, address) ); address[] memory assets = new address[](1); assets[0] = _bearingToken; IRewardsController(rewardsController).claimAllRewards(assets, _recipient); } function getUpdatedInterest( address _poolAddress, ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata ) external view override returns (uint256 totalInterest) { (totalInterest, ) = calculateGeneratedInterest( _poolAddress, _poolData, 0, true ); } function getAccumulatedInterest( address _poolAddress, ILendingStorageManager.PoolStorage calldata _poolData, bytes calldata ) external view override returns (uint256 totalInterest) { (totalInterest, ) = calculateGeneratedInterest( _poolAddress, _poolData, 0, true ); } function getInterestBearingToken(address _collateral, bytes calldata _args) external view override returns (address token) { (address moneyMarket, ) = abi.decode(_args, (address, address)); token = IPool(moneyMarket).getReserveData(_collateral).aTokenAddress; require(token != address(0), 'Interest token not found'); } function collateralToInterestToken( uint256 _collateralAmount, address, address, bytes calldata ) external pure override returns (uint256 interestTokenAmount) { interestTokenAmount = _collateralAmount; } function interestTokenToCollateral( uint256 _interestTokenAmount, address, address, bytes calldata ) external pure override returns (uint256 collateralAmount) { collateralAmount = _interestTokenAmount; } function calculateGeneratedInterest( address _poolAddress, ILendingStorageManager.PoolStorage calldata _pool, uint256 _amount, bool _isDeposit ) internal view returns (uint256 totalInterestGenerated, uint256 poolBalance) { // get current pool total amount of collateral poolBalance = IERC20(_pool.interestBearingToken).balanceOf(_poolAddress); // the total interest is delta between current balance and lastBalance totalInterestGenerated = _isDeposit ? poolBalance - _pool.collateralDeposited - _pool.unclaimedDaoCommission - _pool.unclaimedDaoJRT : poolBalance + _amount - _pool.collateralDeposited - _pool.unclaimedDaoCommission - _pool.unclaimedDaoJRT; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; interface IPool { struct ReserveConfigurationMap { uint256 data; } struct ReserveData { //stores the reserve configuration ReserveConfigurationMap configuration; //the liquidity index. Expressed in ray uint128 liquidityIndex; //the current supply rate. Expressed in ray uint128 currentLiquidityRate; //variable borrow index. Expressed in ray uint128 variableBorrowIndex; //the current variable borrow rate. Expressed in ray uint128 currentVariableBorrowRate; //the current stable borrow rate. Expressed in ray uint128 currentStableBorrowRate; //timestamp of last update uint40 lastUpdateTimestamp; //the id of the reserve. Represents the position in the list of the active reserves uint16 id; //aToken address address aTokenAddress; //stableDebtToken address address stableDebtTokenAddress; //variableDebtToken address address variableDebtTokenAddress; //address of the interest rate strategy address interestRateStrategyAddress; //the current treasury balance, scaled uint128 accruedToTreasury; //the outstanding unbacked aTokens minted through the bridging feature uint128 unbacked; //the outstanding debt borrowed against this asset in isolation mode uint128 isolationModeTotalDebt; } /** * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. * - E.g. User supplies 100 USDC and gets in return 100 aUSDC * @param _asset The address of the underlying asset to supply * @param _amount The amount to be supplied * @param _onBehalfOf The address that will receive the aTokens, same as msg.sender if the user * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens * is a different wallet * @param _referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man **/ function supply( address _asset, uint256 _amount, address _onBehalfOf, uint16 _referralCode ) external; /** * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC * @param _asset The address of the underlying asset to withdraw * @param _amount The underlying amount to be withdrawn * - Send the value type(uint256).max in order to withdraw the whole aToken balance * @param _to The address that will receive the underlying, same as msg.sender if the user * wants to receive it on his own wallet, or a different address if the beneficiary is a * different wallet * @return The final amount withdrawn **/ function withdraw( address _asset, uint256 _amount, address _to ) external returns (uint256); /** * @notice Returns the state and configuration of the reserve * @param _asset The address of the underlying asset of the reserve * @return The state and configuration data of the reserve **/ function getReserveData(address _asset) external view returns (ReserveData memory); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {ISynthereumFinder} from './interfaces/IFinder.sol'; import {AccessControlEnumerable} from '../../@openzeppelin/contracts/access/AccessControlEnumerable.sol'; /** * @title Provides addresses of contracts implementing certain interfaces. */ contract SynthereumFinder is ISynthereumFinder, AccessControlEnumerable { bytes32 public constant MAINTAINER_ROLE = keccak256('Maintainer'); //Describe role structure struct Roles { address admin; address maintainer; } //---------------------------------------- // Storage //---------------------------------------- mapping(bytes32 => address) public interfacesImplemented; //---------------------------------------- // Events //---------------------------------------- event InterfaceImplementationChanged( bytes32 indexed interfaceName, address indexed newImplementationAddress ); //---------------------------------------- // Modifiers //---------------------------------------- modifier onlyMaintainer() { require( hasRole(MAINTAINER_ROLE, msg.sender), 'Sender must be the maintainer' ); _; } //---------------------------------------- // Constructors //---------------------------------------- constructor(Roles memory roles) { _setRoleAdmin(DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_ROLE); _setRoleAdmin(MAINTAINER_ROLE, DEFAULT_ADMIN_ROLE); _setupRole(DEFAULT_ADMIN_ROLE, roles.admin); _setupRole(MAINTAINER_ROLE, roles.maintainer); } //---------------------------------------- // External view //---------------------------------------- /** * @notice Updates the address of the contract that implements `interfaceName`. * @param interfaceName bytes32 of the interface name that is either changed or registered. * @param implementationAddress address of the implementation contract. */ function changeImplementationAddress( bytes32 interfaceName, address implementationAddress ) external override onlyMaintainer { interfacesImplemented[interfaceName] = implementationAddress; emit InterfaceImplementationChanged(interfaceName, implementationAddress); } /** * @notice Gets the address of the contract that implements the given `interfaceName`. * @param interfaceName queried interface. * @return implementationAddress Address of the defined interface. */ function getImplementationAddress(bytes32 interfaceName) external view override returns (address) { address implementationAddress = interfacesImplemented[interfaceName]; require(implementationAddress != address(0x0), 'Implementation not found'); return implementationAddress; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract ISynthereumFinder","name":"_finder","type":"address"},{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"maintainer","type":"address"}],"internalType":"struct ILendingManager.Roles","name":"_roles","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"collateralIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"JRTOut","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"BatchBuyback","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"collateralOut","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"BatchCommissionClaim","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"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAINTAINER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_swapModule","type":"address"}],"name":"addSwapProtocol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_pools","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_collateralAddress","type":"address"},{"internalType":"bytes","name":"_swapParams","type":"bytes"}],"name":"batchBuyback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_pools","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"batchClaimCommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_pools","type":"address[]"}],"name":"claimLendingRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"uint256","name":"_collateralAmount","type":"uint256"}],"name":"collateralToInterestToken","outputs":[{"internalType":"uint256","name":"interestTokenAmount","type":"uint256"},{"internalType":"address","name":"interestTokenAddr","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[{"components":[{"internalType":"uint256","name":"poolInterest","type":"uint256"},{"internalType":"uint256","name":"daoInterest","type":"uint256"},{"internalType":"uint256","name":"tokensOut","type":"uint256"},{"internalType":"uint256","name":"tokensTransferred","type":"uint256"},{"internalType":"uint256","name":"prevTotalCollateral","type":"uint256"}],"internalType":"struct ILendingManager.ReturnValues","name":"returnValues","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"}],"name":"getAccumulatedInterest","outputs":[{"internalType":"uint256","name":"poolInterest","type":"uint256"},{"internalType":"uint256","name":"commissionInterest","type":"uint256"},{"internalType":"uint256","name":"buybackInterest","type":"uint256"},{"internalType":"uint256","name":"collateralDeposited","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":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"_pool","type":"address"},{"internalType":"uint256","name":"_interestTokenAmount","type":"uint256"}],"name":"interestTokenToCollateral","outputs":[{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"address","name":"interestTokenAddr","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_newLendingID","type":"string"},{"internalType":"address","name":"_newInterestBearingToken","type":"address"},{"internalType":"uint256","name":"_interestTokenAmount","type":"uint256"}],"name":"migrateLendingModule","outputs":[{"components":[{"internalType":"uint256","name":"prevTotalCollateral","type":"uint256"},{"internalType":"uint256","name":"poolInterest","type":"uint256"},{"internalType":"uint256","name":"actualTotalCollateral","type":"uint256"}],"internalType":"struct ILendingManager.MigrateReturnValues","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_migrationPool","type":"address"},{"internalType":"address","name":"_newPool","type":"address"}],"name":"migratePool","outputs":[{"internalType":"uint256","name":"sourceCollateralAmount","type":"uint256"},{"internalType":"uint256","name":"actualCollateralAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapModule","type":"address"}],"name":"removeSwapProtocol","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"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_id","type":"string"},{"components":[{"internalType":"address","name":"lendingModule","type":"address"},{"internalType":"bytes","name":"args","type":"bytes"}],"internalType":"struct ILendingStorageManager.LendingInfo","name":"_lendingInfo","type":"tuple"}],"name":"setLendingModule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"uint64","name":"_daoInterestShare","type":"uint64"},{"internalType":"uint64","name":"_jrtBuybackShare","type":"uint64"}],"name":"setShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"address","name":"_swapModule","type":"address"}],"name":"setSwapModule","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":[],"name":"updateAccumulatedInterest","outputs":[{"components":[{"internalType":"uint256","name":"poolInterest","type":"uint256"},{"internalType":"uint256","name":"daoInterest","type":"uint256"},{"internalType":"uint256","name":"tokensOut","type":"uint256"},{"internalType":"uint256","name":"tokensTransferred","type":"uint256"},{"internalType":"uint256","name":"prevTotalCollateral","type":"uint256"}],"internalType":"struct ILendingManager.ReturnValues","name":"returnValues","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_interestTokenAmount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdraw","outputs":[{"components":[{"internalType":"uint256","name":"poolInterest","type":"uint256"},{"internalType":"uint256","name":"daoInterest","type":"uint256"},{"internalType":"uint256","name":"tokensOut","type":"uint256"},{"internalType":"uint256","name":"tokensTransferred","type":"uint256"},{"internalType":"uint256","name":"prevTotalCollateral","type":"uint256"}],"internalType":"struct ILendingManager.ReturnValues","name":"returnValues","type":"tuple"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
610100604052603060a0818152906200459560c03980516200002a91600391602090910190620002a4565b50604051806060016040528060348152602001620045c56034913980516200005b91600491602090910190620002a4565b503480156200006957600080fd5b5060405162004619380380620046198339810160408190526200008c9162000363565b600260009081556001600160a01b038316608052620000ac90806200010a565b620000c8600080516020620045f983398151915260006200010a565b8051620000d89060009062000157565b620000fd600080516020620045f983398151915282602001516200015760201b60201c565b505060016000556200043e565b6000828152600160208190526040808320909101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b6200016e82826200019a60201b620023ef1760201c565b600082815260026020908152604090912062000195918390620023fd620001aa821b17901c565b505050565b620001a68282620001ca565b5050565b6000620001c1836001600160a01b03841662000252565b90505b92915050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16620001a65760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008181526001830160205260408120546200029b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620001c4565b506000620001c4565b828054620002b29062000401565b90600052602060002090601f016020900481019282620002d6576000855562000321565b82601f10620002f157805160ff191683800117855562000321565b8280016001018555821562000321579182015b828111156200032157825182559160200191906001019062000304565b506200032f92915062000333565b5090565b5b808211156200032f576000815560010162000334565b6001600160a01b03811681146200036057600080fd5b50565b60008082840360608112156200037857600080fd5b835162000385816200034a565b92506040601f19820112156200039a57600080fd5b50604080519081016001600160401b0381118282101715620003cc57634e487b7160e01b600052604160045260246000fd5b6040526020840151620003df816200034a565b81526040840151620003f1816200034a565b6020820152919491935090915050565b600181811c908216806200041657607f821691505b602082108114156200043857634e487b7160e01b600052602260045260246000fd5b50919050565b6080516141186200047d6000396000818161079101528181610b4b015281816112f80152818161173301528181611c81015261260101526141186000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806391d14854116100de578063ca15c87311610097578063db456b6211610071578063db456b6214610431578063de3627c714610444578063eead906a14610457578063f87422541461045f57600080fd5b8063ca15c873146103f8578063d547741f1461040b578063d612ea331461041e57600080fd5b806391d148541461037457806399dce61b14610387578063a217fddf146103b7578063a2be10bd146103bf578063aa566a62146103d2578063b6b55f25146103e557600080fd5b8063366694131161014b5780636c924f2f116101255780636c924f2f146102db57806374e44a97146102ee578063772b7e97146103215780639010d07c1461034957600080fd5b8063366694131461028057806338f6c371146102b5578063658c9a09146102c857600080fd5b8062f714ce1461019257806301ffc9a7146101f0578063220ea31d14610213578063248a9ca3146102285780632f2ff15d1461025a57806336568abe1461026d575b600080fd5b6101a56101a03660046131a0565b610474565b6040516101e79190600060a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b60405180910390f35b6102036101fe3660046131d0565b6106ac565b60405190151581526020016101e7565b610226610221366004613286565b6106d7565b005b61024c610236366004613334565b6000908152600160208190526040909120015490565b6040519081526020016101e7565b6102266102683660046131a0565b610d23565b61022661027b3660046131a0565b610d4a565b61029361028e366004613405565b610d6c565b60408051825181526020808401519082015291810151908201526060016101e7565b6102266102c33660046134a1565b61115e565b6102266102d63660046134cf565b611235565b6102266102e9366004613525565b6114e1565b6103016102fc366004613570565b6115c9565b6040805194855260208501939093529183015260608201526080016101e7565b61033461032f3660046134a1565b61172b565b604080519283526020830191909152016101e7565b61035c61035736600461358d565b61198d565b6040516001600160a01b0390911681526020016101e7565b6102036103823660046131a0565b6119ac565b61039a6103953660046135af565b6119d7565b604080519283526001600160a01b039091166020830152016101e7565b61024c600081565b6102266103cd366004613570565b611b13565b6102266103e03660046135db565b611be2565b6101a56103f3366004613334565b611e0a565b61024c610406366004613334565b611fdd565b6102266104193660046131a0565b611ff4565b61039a61042c3660046135af565b611ffe565b61022661043f366004613570565b6120d7565b610226610452366004613646565b61216f565b6101a5612208565b61024c60008051602061400683398151915281565b6104a66040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b600260005414156104d25760405162461bcd60e51b81526004016104c9906136aa565b60405180910390fd5b6002600090815580806104e3612412565b925092509250600061057a6040518060a001604052806067815260200161402660679139853386602001518b8b6040516024016105249594939291906137a9565b60408051601f19818403018152908290529161053f916137fb565b6040519081900390206020820180516001600160e01b03166001600160e01b031990921691909117905284516001600160a01b0316906124f5565b90506000818060200190518101906105929190613817565b905060006105ad82600001518760e001518860a0015161251a565b9050836001600160a01b031663120b8e5033846020015184600001518a602001516105d89190613888565b6105e291906138a0565b84602001518a604001516105f69190613888565b85604001518b6060015161060a9190613888565b6040518563ffffffff1660e01b815260040161062994939291906138b7565b600060405180830381600087803b15801561064357600080fd5b505af1158015610657573d6000803e3d6000fd5b5050506020808401516040808b01919091528085015160608b015283518a5290830151908301516106889250613888565b60208089019190915295909501516080870152505060016000555091949350505050565b60006001600160e01b03198216635a05180f60e01b14806106d157506106d18261259c565b92915050565b6106ef600080516020614006833981519152336119ac565b61070b5760405162461bcd60e51b81526004016104c9906138dd565b8584146107495760405162461bcd60e51b815260206004820152600c60248201526b125b9d985b1a590818d85b1b60a21b60448201526064016104c9565b60006107536125d1565b6040516302abf57960e61b815275213abcb130b1b5a83937b3b930b6a932b1b2b4bb32b960511b600482015290915060009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063aafd5e409060240160206040518083038186803b1580156107d357600080fd5b505afa1580156107e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080b9190613924565b905060005b60ff81168a1115610b245760008b8b8360ff1681811061083257610832613941565b90506020020160208101906108479190613570565b905060008a8a8460ff1681811061086057610860613941565b6040516313d21cdf60e01b81526001600160a01b038681166004830152602090920293909301359350600092839250908916906313d21cdf9060240160006040518083038186803b1580156108b457600080fd5b505afa1580156108c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108f091908101906139f7565b915091508a6001600160a01b031682608001516001600160a01b03161461094f5760405162461bcd60e51b8152602060048201526013602482015272086ded8d8c2e8cae4c2d840dad2e6dac2e8c6d606b1b60448201526064016104c9565b600061095b8585611ffe565b5060405163152a13cd60e31b8152600481018290529091506001600160a01b0386169063a9509e6890602401602060405180830381600087803b1580156109a157600080fd5b505af11580156109b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d99190613abc565b90506000610a166040518060a0016040528060678152602001614026606791398588866020015186306040516024016105249594939291906137a9565b9050600081806020019051810190610a2e9190613817565b905080604001518a610a409190613888565b99506000610a5b82600001518760e001518860a0015161251a565b90508b6001600160a01b031663120b8e508983600001518960200151610a819190613888565b856020015185602001518b60400151610a9a9190613888565b610aa491906138a0565b85604001518b60600151610ab89190613888565b6040518563ffffffff1660e01b8152600401610ad794939291906138b7565b600060405180830381600087803b158015610af157600080fd5b505af1158015610b05573d6000803e3d6000fd5b5050505050505050505050508080610b1c90613ad5565b915050610810565b506040516302abf57960e61b81526a2530b93b34b9aa37b5b2b760a91b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063aafd5e409060240160206040518083038186803b158015610b9557600080fd5b505afa158015610ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcd9190613924565b90506000610cbe6003848a85888c8c604051602401610bf196959493929190613b1e565b60408051601f198184030181529082905291610c0c91613b66565b60408051918290039091206020830180516001600160e01b03166001600160e01b0319909216919091179052516326a966c160e11b81526001600160a01b038b81166004830152881690634d52cd829060240160206040518083038186803b158015610c7757600080fd5b505afa158015610c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610caf9190613924565b6001600160a01b0316906124f5565b9050837f15bc7538235a26bbf90ff27a286d54cc1f91d523cbf888e6a739fd36621ec50d82806020019051810190610cf69190613abc565b604080519182526001600160a01b03871660208301520160405180910390a2505050505050505050505050565b610d2d8282612688565b6000828152600260205260409020610d4590826123fd565b505050565b610d5482826126af565b6000828152600260205260409020610d459082612729565b610d9060405180606001604052806000815260200160008152602001600081525090565b60026000541415610db35760405162461bcd60e51b81526004016104c9906136aa565b600260009081558080610dc4612412565b925092509250600083602001519050610df760405180606001604052806000815260200160008152602001600081525090565b6000610e886040518060a001604052806067815260200161402660679139873388602001518c30604051602401610e329594939291906137a9565b60408051601f198184030181529082905291610e4d916137fb565b6040519081900390206020820180516001600160e01b03166001600160e01b031990921691909117905286516001600160a01b0316906124f5565b905080806020019051810190610e9e9190613817565b9150506000610eba82600001518760e001518860a0015161251a565b9050600081602001518760400151610ed29190613888565b9050600082604001518860600151610eea9190613888565b604051630120b8e560e41b81529091506001600160a01b0387169063120b8e5090610f20903390600090819081906004016138b7565b600060405180830381600087803b158015610f3a57600080fd5b505af1158015610f4e573d6000803e3d6000fd5b50505050610f6d60408051808201909152600081526060602082015290565b866001600160a01b031663ee3b32698e338f6040518463ffffffff1660e01b8152600401610f9d93929190613c02565b600060405180830381600087803b158015610fb757600080fd5b505af1158015610fcb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ff391908101906139f7565b809250819a505050600061108e60405180608001604052806056815260200161408d605691398b84602001518960400151336040516024016110389493929190613c35565b60408051601f198184030181529082905291611053916137fb565b6040519081900390206020820180516001600160e01b03166001600160e01b031990921691909117905283516001600160a01b0316906124f5565b90506000818060200190518101906110a69190613817565b90506000848683602001516110bb91906138a0565b6110c591906138a0565b604051630120b8e560e41b81529091506001600160a01b038b169063120b8e50906110fa90339085908b908b906004016138b7565b600060405180830381600087803b15801561111457600080fd5b505af1158015611128573d6000803e3d6000fd5b5050604080516060810182529b8c52985160208c01525050958801959095525050600160005550929a9950505050505050505050565b611176600080516020614006833981519152336119ac565b6111925760405162461bcd60e51b81526004016104c9906138dd565b600260005414156111b55760405162461bcd60e51b81526004016104c9906136aa565b600260009081556111c46125d1565b6040516338f6c37160e01b81526001600160a01b0385811660048301528481166024830152919250908216906338f6c37190604401600060405180830381600087803b15801561121357600080fd5b505af1158015611227573d6000803e3d6000fd5b505060016000555050505050565b61124d600080516020614006833981519152336119ac565b6112695760405162461bcd60e51b81526004016104c9906138dd565b6002600054141561128c5760405162461bcd60e51b81526004016104c9906136aa565b6002600090815561129b6125d1565b60408051808201909152600080825260208201529091506040805180820190915260008152606060208201526040516302abf57960e61b8152752632b73234b733a932bbb0b93239a932b1b2b4bb32b960511b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063aafd5e409060240160206040518083038186803b15801561134257600080fd5b505afa158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a9190613924565b905060005b60ff811686111561122757846001600160a01b0316632155162388888460ff168181106113ae576113ae613941565b90506020020160208101906113c39190613570565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160006040518083038186803b15801561140257600080fd5b505afa158015611416573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261143e9190810190613c7b565b9094509250868660ff831681811061145857611458613941565b905060200201602081019061146d9190613570565b6001600160a01b0316634f9b84778486856040518463ffffffff1660e01b815260040161149c93929190613ce2565b600060405180830381600087803b1580156114b657600080fd5b505af11580156114ca573d6000803e3d6000fd5b5050505080806114d990613ad5565b91505061137f565b6114f9600080516020614006833981519152336119ac565b6115155760405162461bcd60e51b81526004016104c9906138dd565b600260005414156115385760405162461bcd60e51b81526004016104c9906136aa565b600260009081556115476125d1565b604051636c924f2f60e01b81526001600160a01b0386811660048301526001600160401b0380871660248401528516604483015291925090821690636c924f2f906064015b600060405180830381600087803b1580156115a657600080fd5b505af11580156115ba573d6000803e3d6000fd5b50506001600055505050505050565b60008060008060006115d96125d1565b6040516313d21cdf60e01b81526001600160a01b0388811660048301529192506000918291908416906313d21cdf9060240160006040518083038186803b15801561162357600080fd5b505afa158015611637573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261165f91908101906139f7565b91509150600081600001516001600160a01b03166317e386468a8585602001516040518463ffffffff1660e01b815260040161169d93929190613d3a565b60206040518083038186803b1580156116b557600080fd5b505afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190613abc565b90506000611704828560e001518660a0015161251a565b805160408201516020928301519690920151909c919b509499509397509295505050505050565b6000806117577f000000000000000000000000000000000000000000000000000000000000000061273e565b6002600054141561177a5760405162461bcd60e51b81526004016104c9906136aa565b600260009081556117896125d1565b604051632155162360e01b81526001600160a01b03878116600483015291925060009182919084169063215516239060240160006040518083038186803b1580156117d357600080fd5b505afa1580156117e7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261180f9190810190613c7b565b91509150600061185a6004898986600001518760200151876020015160405160240161183f959493929190613d6b565b60408051601f19818403018152908290529161105391613b66565b9050600080828060200190518101906118739190613db2565b604051637d9d518b60e01b81526001600160a01b038d8116600483015292945090925090871690637d9d518b9060240160206040518083038186803b1580156118bb57600080fd5b505afa1580156118cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f39190613abc565b975081611900828a613888565b61190a91906138a0565b6040516340ec3c6160e11b81526001600160a01b038c811660048301528b8116602483015260448201839052919850908716906381d878c290606401600060405180830381600087803b15801561196057600080fd5b505af1158015611974573d6000803e3d6000fd5b5050505050505050505060016000819055509250929050565b60008281526002602052604081206119a590836128ac565b9392505050565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60008060006119e46125d1565b604051632155162360e01b81526001600160a01b03878116600483015291925060009182919084169063215516239060240160006040518083038186803b158015611a2e57600080fd5b505afa158015611a42573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a6a9190810190613c7b565b9150915080600001516001600160a01b0316633ca5578c878460000151856020015185602001516040518563ffffffff1660e01b8152600401611ab09493929190613dd6565b60206040518083038186803b158015611ac857600080fd5b505afa158015611adc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b009190613abc565b9450816020015193505050509250929050565b611b2b600080516020614006833981519152336119ac565b611b475760405162461bcd60e51b81526004016104c9906138dd565b60026000541415611b6a5760405162461bcd60e51b81526004016104c9906136aa565b60026000908155611b796125d1565b60405163a2be10bd60e01b81526001600160a01b0384811660048301529192509082169063a2be10bd906024015b600060405180830381600087803b158015611bc157600080fd5b505af1158015611bd5573d6000803e3d6000fd5b5050600160005550505050565b611bfa600080516020614006833981519152336119ac565b611c165760405162461bcd60e51b81526004016104c9906138dd565b828114611c545760405162461bcd60e51b815260206004820152600c60248201526b125b9d985b1a590818d85b1b60a21b60448201526064016104c9565b6040516302abf57960e61b81527121b7b6b6b4b9b9b4b7b72932b1b2b4bb32b960711b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063aafd5e409060240160206040518083038186803b158015611ccb57600080fd5b505afa158015611cdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d039190613924565b90506000805b60ff8116861115611dc357600085858360ff16818110611d2b57611d2b613941565b905060200201351115611db157611d8787878360ff16818110611d5057611d50613941565b9050602002016020810190611d659190613570565b86868460ff16818110611d7a57611d7a613941565b90506020020135856128b8565b84848260ff16818110611d9c57611d9c613941565b9050602002013582611dae9190613888565b91505b80611dbb81613ad5565b915050611d09565b506040516001600160a01b038316815281907f47592ec9d9991a137422beab7c67c9dde0899a7b5cc3c7df0812979abf5be8ac9060200160405180910390a2505050505050565b611e3c6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60026000541415611e5f5760405162461bcd60e51b81526004016104c9906136aa565b600260009081558080611e70612412565b9250925092506000611eac60405180608001604052806056815260200161408d6056913960208501516040516105249188918b90602401613e08565b9050600081806020019051810190611ec49190613817565b90506000611edf82600001518760e001518860a0015161251a565b9050836001600160a01b031663120b8e5033836000015185602001518a60200151611f0a9190613888565b611f149190613888565b84602001518a60400151611f289190613888565b85604001518b60600151611f3c9190613888565b6040518563ffffffff1660e01b8152600401611f5b94939291906138b7565b600060405180830381600087803b158015611f7557600080fd5b505af1158015611f89573d6000803e3d6000fd5b5050506020808401516040808b01919091528085015160608b015283518a529083015190830151611fba9250613888565b602080890191909152959095015160808701525050600160005550919392505050565b60008181526002602052604081206106d190612b00565b610d548282612b0a565b600080600061200b6125d1565b604051632155162360e01b81526001600160a01b03878116600483015291925060009182919084169063215516239060240160006040518083038186803b15801561205557600080fd5b505afa158015612069573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120919190810190613c7b565b9150915080600001516001600160a01b031663156b8523878460000151856020015185602001516040518563ffffffff1660e01b8152600401611ab09493929190613dd6565b6120ef600080516020614006833981519152336119ac565b61210b5760405162461bcd60e51b81526004016104c9906138dd565b6002600054141561212e5760405162461bcd60e51b81526004016104c9906136aa565b6002600090815561213d6125d1565b604051636da2b5b160e11b81526001600160a01b0384811660048301529192509082169063db456b6290602401611ba7565b612187600080516020614006833981519152336119ac565b6121a35760405162461bcd60e51b81526004016104c9906138dd565b600260005414156121c65760405162461bcd60e51b81526004016104c9906136aa565b600260009081556121d56125d1565b60405163de3627c760e01b81529091506001600160a01b0382169063de3627c79061158c90879087908790600401613e3c565b61223a6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6002600054141561225d5760405162461bcd60e51b81526004016104c9906136aa565b60026000908155808061226e612412565b925092509250600082600001516001600160a01b031663b108ba2c338686602001516040518463ffffffff1660e01b81526004016122ae93929190613d3a565b602060405180830381600087803b1580156122c857600080fd5b505af11580156122dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123009190613abc565b90506000612317828660e001518760a0015161251a565b9050826001600160a01b031663120b8e50338360000151886020015161233d9190613888565b846020015189604001516123519190613888565b85604001518a606001516123659190613888565b6040518563ffffffff1660e01b815260040161238494939291906138b7565b600060405180830381600087803b15801561239e57600080fd5b505af11580156123b2573d6000803e3d6000fd5b5050825188525050604081015160208201516123ce9190613888565b60208088019190915294909401516080860152505060016000555090919050565b6123f98282612b31565b5050565b60006119a5836001600160a01b038416612b9c565b60408051610100810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905260c0840183905260e08401839052845180860190955291845283015290600061246d6125d1565b6040516313d21cdf60e01b81523360048201529091506001600160a01b038216906313d21cdf9060240160006040518083038186803b1580156124af57600080fd5b505afa1580156124c3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124eb91908101906139f7565b9094909350909150565b60606119a58383604051806060016040528060278152602001613fdf60279139612beb565b61253e60405180606001604052806000815260200160008152602001600081525090565b83612548576119a5565b600061255d856001600160401b038616612cbf565b9050612572816001600160401b038516612cbf565b6020830181905261258390826138a0565b604083015261259281866138a0565b8252509392505050565b60006001600160e01b03198216637965db0b60e01b14806106d157506301ffc9a760e01b6001600160e01b03198316146106d1565b6040516302abf57960e61b8152742632b73234b733a9ba37b930b3b2a6b0b730b3b2b960591b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063aafd5e409060240160206040518083038186803b15801561264b57600080fd5b505afa15801561265f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126839190613924565b905090565b600082815260016020819052604090912001546126a58133612cde565b610d458383612b31565b6001600160a01b038116331461271f5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016104c9565b6123f98282612d42565b60006119a5836001600160a01b038416612da9565b6040516302abf57960e61b815270466163746f727956657273696f6e696e6760781b60048201526000906001600160a01b0383169063aafd5e409060240160206040518083038186803b15801561279457600080fd5b505afa1580156127a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127cc9190613924565b604051636d2721a360e11b81526a506f6f6c466163746f727960a81b60048201529091506000906001600160a01b0383169063da4e43469060240160206040518083038186803b15801561281f57600080fd5b505afa158015612833573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128579190613ec5565b905061287282826a506f6f6c466163746f727960a81b612e9c565b610d455760405162461bcd60e51b815260206004820152600b60248201526a139bdd08185b1b1bddd95960aa1b60448201526064016104c9565b60006119a58383612f8a565b60006128c26125d1565b6040516313d21cdf60e01b81526001600160a01b0386811660048301529192506000918291908416906313d21cdf9060240160006040518083038186803b15801561290c57600080fd5b505afa158015612920573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261294891908101906139f7565b9150915060006129588787611ffe565b5060405163152a13cd60e31b8152600481018290529091506001600160a01b0388169063a9509e6890602401602060405180830381600087803b15801561299e57600080fd5b505af11580156129b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d69190613abc565b90506000612a136040518060a001604052806067815260200161402660679139858a8660200151868b6040516024016105249594939291906137a9565b9050600081806020019051810190612a2b9190613817565b90506000612a4682600001518760e001518860a0015161251a565b9050866001600160a01b031663120b8e508b83600001518960200151612a6c9190613888565b84602001518a60400151612a809190613888565b866020015186604001518c60600151612a999190613888565b612aa391906138a0565b6040518563ffffffff1660e01b8152600401612ac294939291906138b7565b600060405180830381600087803b158015612adc57600080fd5b505af1158015612af0573d6000803e3d6000fd5b5050505050505050505050505050565b60006106d1825490565b60008281526001602081905260409091200154612b278133612cde565b610d458383612d42565b612b3b82826119ac565b6123f95760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6000818152600183016020526040812054612be3575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106d1565b5060006106d1565b6060833b612c4a5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016104c9565b600080856001600160a01b031685604051612c6591906137fb565b600060405180830381855af49150503d8060008114612ca0576040519150601f19603f3d011682016040523d82523d6000602084013e612ca5565b606091505b5091509150612cb5828286612fb4565b9695505050505050565b6000670de0b6b3a7640000612cd48385613ee8565b6119a59190613f07565b612ce882826119ac565b6123f957612d00816001600160a01b03166014612fed565b612d0b836020612fed565b604051602001612d1c929190613f29565b60408051601f198184030181529082905262461bcd60e51b82526104c991600401613f9e565b612d4c82826119ac565b156123f95760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008181526001830160205260408120548015612e92576000612dcd6001836138a0565b8554909150600090612de1906001906138a0565b9050818114612e46576000866000018281548110612e0157612e01613941565b9060005260206000200154905080876000018481548110612e2457612e24613941565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612e5757612e57613fb1565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106d1565b60009150506106d1565b60008060005b8460ff168260ff161015612f8157604051636839980160e11b81526004810185905260ff821660248201526001600160a01b0387169063d07330029060440160206040518083038186803b158015612ef957600080fd5b505afa925050508015612f29575060408051601f3d908101601f19168201909252612f2691810190613924565b60015b612f3257612f6f565b336001600160a01b0382161415612f4d576001935050612f81565b82612f5781613ad5565b9350508560ff168360ff161415612f6d57600093505b505b80612f7981613ad5565b915050612ea2565b50509392505050565b6000826000018281548110612fa157612fa1613941565b9060005260206000200154905092915050565b60608315612fc35750816119a5565b825115612fd35782518084602001fd5b8160405162461bcd60e51b81526004016104c99190613f9e565b60606000612ffc836002613ee8565b613007906002613888565b6001600160401b0381111561301e5761301e61334d565b6040519080825280601f01601f191660200182016040528015613048576020820181803683370190505b509050600360fc1b8160008151811061306357613063613941565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061309257613092613941565b60200101906001600160f81b031916908160001a90535060006130b6846002613ee8565b6130c1906001613888565b90505b6001811115613139576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106130f5576130f5613941565b1a60f81b82828151811061310b5761310b613941565b60200101906001600160f81b031916908160001a90535060049490941c9361313281613fc7565b90506130c4565b5083156119a55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016104c9565b6001600160a01b038116811461319d57600080fd5b50565b600080604083850312156131b357600080fd5b8235915060208301356131c581613188565b809150509250929050565b6000602082840312156131e257600080fd5b81356001600160e01b0319811681146119a557600080fd5b60008083601f84011261320c57600080fd5b5081356001600160401b0381111561322357600080fd5b6020830191508360208260051b850101111561323e57600080fd5b9250929050565b60008083601f84011261325757600080fd5b5081356001600160401b0381111561326e57600080fd5b60208301915083602082850101111561323e57600080fd5b60008060008060008060006080888a0312156132a157600080fd5b87356001600160401b03808211156132b857600080fd5b6132c48b838c016131fa565b909950975060208a01359150808211156132dd57600080fd5b6132e98b838c016131fa565b909750955060408a013591506132fe82613188565b9093506060890135908082111561331457600080fd5b506133218a828b01613245565b989b979a50959850939692959293505050565b60006020828403121561334657600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156133855761338561334d565b60405290565b60405161010081016001600160401b03811182821017156133855761338561334d565b604051601f8201601f191681016001600160401b03811182821017156133d6576133d661334d565b604052919050565b60006001600160401b038211156133f7576133f761334d565b50601f01601f191660200190565b60008060006060848603121561341a57600080fd5b83356001600160401b0381111561343057600080fd5b8401601f8101861361344157600080fd5b803561345461344f826133de565b6133ae565b81815287602083850101111561346957600080fd5b81602084016020830137600060208383010152809550505050602084013561349081613188565b929592945050506040919091013590565b600080604083850312156134b457600080fd5b82356134bf81613188565b915060208301356131c581613188565b600080602083850312156134e257600080fd5b82356001600160401b038111156134f857600080fd5b613504858286016131fa565b90969095509350505050565b6001600160401b038116811461319d57600080fd5b60008060006060848603121561353a57600080fd5b833561354581613188565b9250602084013561355581613510565b9150604084013561356581613510565b809150509250925092565b60006020828403121561358257600080fd5b81356119a581613188565b600080604083850312156135a057600080fd5b50508035926020909101359150565b600080604083850312156135c257600080fd5b82356135cd81613188565b946020939093013593505050565b600080600080604085870312156135f157600080fd5b84356001600160401b038082111561360857600080fd5b613614888389016131fa565b9096509450602087013591508082111561362d57600080fd5b5061363a878288016131fa565b95989497509550505050565b60008060006040848603121561365b57600080fd5b83356001600160401b038082111561367257600080fd5b61367e87838801613245565b9095509350602086013591508082111561369757600080fd5b5084016040818703121561356557600080fd5b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b80518252602081015160208301526040810151604083015260608101516060830152608081015160018060a01b03808216608085015260a083015191506001600160401b0380831660a08601528160c08501511660c08601528060e08501511660e08601525050505050565b60005b83811015613768578181015183820152602001613750565b83811115613777576000848401525b50505050565b6000815180845261379581602086016020860161374d565b601f01601f19169290920160200192915050565b60006101806137b883896136e1565b6001600160a01b0387811661010085015261012084018290526137dd8285018861377d565b92508561014085015280851661016085015250509695505050505050565b6000825161380d81846020870161374d565b9190910192915050565b60006060828403121561382957600080fd5b604051606081018181106001600160401b038211171561384b5761384b61334d565b80604052508251815260208301516020820152604083015160408201528091505092915050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561389b5761389b613872565b500190565b6000828210156138b2576138b2613872565b500390565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b6020808252601d908201527f53656e646572206d75737420626520746865206d61696e7461696e6572000000604082015260600190565b805161391f81613188565b919050565b60006020828403121561393657600080fd5b81516119a581613188565b634e487b7160e01b600052603260045260246000fd5b805161391f81613510565b60006040828403121561397457600080fd5b61397c613363565b9050815161398981613188565b815260208201516001600160401b038111156139a457600080fd5b8201601f810184136139b557600080fd5b80516139c361344f826133de565b8181528560208385010111156139d857600080fd5b6139e982602083016020860161374d565b602084015250909392505050565b600080828403610120811215613a0c57600080fd5b61010080821215613a1c57600080fd5b613a2461338b565b915084518252602085015160208301526040850151604083015260608501516060830152613a5460808601613914565b6080830152613a6560a08601613957565b60a0830152613a7660c08601613914565b60c0830152613a8760e08601613957565b60e08301528401519092506001600160401b03811115613aa657600080fd5b613ab285828601613962565b9150509250929050565b600060208284031215613ace57600080fd5b5051919050565b600060ff821660ff811415613aec57613aec613872565b60010192915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0387811682528681166020830152851660408201526060810184905260a060808201819052600090613b5a9083018486613af5565b98975050505050505050565b600080835481600182811c915080831680613b8257607f831692505b6020808410821415613ba257634e487b7160e01b86526022600452602486fd5b818015613bb65760018114613bc757613bf4565b60ff19861689528489019650613bf4565b60008a81526020902060005b86811015613bec5781548b820152908501908301613bd3565b505084890196505b509498975050505050505050565b606081526000613c15606083018661377d565b6001600160a01b0394851660208401529290931660409091015292915050565b6000610160613c4483886136e1565b80610100840152613c578184018761377d565b61012084019590955250506001600160a01b03919091166101409091015292915050565b6000808284036060811215613c8f57600080fd5b6040811215613c9d57600080fd5b50613ca6613363565b8351613cb181613188565b81526020840151613cc181613188565b602082015260408401519092506001600160401b03811115613aa657600080fd5b60808152600060018060a01b038086511660808401526020860151604060a0850152613d1160c085018261377d565b925050808551166020840152806020860151166040840152808416606084015250949350505050565b6001600160a01b03841681526000610140613d5860208401866136e1565b80610120840152612cb58184018561377d565b6001600160a01b038681168252858116602083015284811660408301528316606082015260a060808201819052600090613da79083018461377d565b979650505050505050565b60008060408385031215613dc557600080fd5b505080516020909101519092909150565b8481526001600160a01b03848116602083015283166040820152608060608201819052600090612cb59083018461377d565b6000610140613e1783876136e1565b80610100840152613e2a8184018661377d565b91505082610120830152949350505050565b604081526000613e50604083018587613af5565b82810360208401528335613e6381613188565b6001600160a01b03168152602084013536859003601e19018112613e8657600080fd5b840180356001600160401b03811115613e9e57600080fd5b803603861315613ead57600080fd5b60406020840152613b5a604084018260208501613af5565b600060208284031215613ed757600080fd5b815160ff811681146119a557600080fd5b6000816000190483118215151615613f0257613f02613872565b500290565b600082613f2457634e487b7160e01b600052601260045260246000fd5b500490565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613f6181601785016020880161374d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351613f9281602884016020880161374d565b01602801949350505050565b6020815260006119a5602083018461377d565b634e487b7160e01b600052603160045260246000fd5b600081613fd657613fd6613872565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564126303c860ea810f85e857ad8768056e2eebc24b7796655ff3107e4af18e3f1e77697468647261772828627974657333322c75696e743235362c75696e743235362c75696e743235362c616464726573732c75696e7436342c616464726573732c75696e743634292c616464726573732c62797465732c75696e743235362c61646472657373296465706f7369742828627974657333322c75696e743235362c75696e743235362c75696e743235362c616464726573732c75696e7436342c616464726573732c75696e743634292c62797465732c75696e7432353629a264697066735822122010722fde9ac9aa3a36d3a34f8e4eedb756ee05f4c3ee6cb32d8b2692ed1a3c4764736f6c6343000809003373776170546f4a525428616464726573732c616464726573732c616464726573732c75696e743235362c627974657329746f74616c5472616e7366657228616464726573732c616464726573732c616464726573732c616464726573732c627974657329126303c860ea810f85e857ad8768056e2eebc24b7796655ff3107e4af18e3f1e00000000000000000000000080d629cf2d775cb9b97c4a95fe2269e0e8459d3a000000000000000000000000b5c54f57d7f3ec6367db4fb5a08a1174797e221c000000000000000000000000d874e1b9ace88bfaf2d5b9859164ac1001b40303
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061018d5760003560e01c806391d14854116100de578063ca15c87311610097578063db456b6211610071578063db456b6214610431578063de3627c714610444578063eead906a14610457578063f87422541461045f57600080fd5b8063ca15c873146103f8578063d547741f1461040b578063d612ea331461041e57600080fd5b806391d148541461037457806399dce61b14610387578063a217fddf146103b7578063a2be10bd146103bf578063aa566a62146103d2578063b6b55f25146103e557600080fd5b8063366694131161014b5780636c924f2f116101255780636c924f2f146102db57806374e44a97146102ee578063772b7e97146103215780639010d07c1461034957600080fd5b8063366694131461028057806338f6c371146102b5578063658c9a09146102c857600080fd5b8062f714ce1461019257806301ffc9a7146101f0578063220ea31d14610213578063248a9ca3146102285780632f2ff15d1461025a57806336568abe1461026d575b600080fd5b6101a56101a03660046131a0565b610474565b6040516101e79190600060a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b60405180910390f35b6102036101fe3660046131d0565b6106ac565b60405190151581526020016101e7565b610226610221366004613286565b6106d7565b005b61024c610236366004613334565b6000908152600160208190526040909120015490565b6040519081526020016101e7565b6102266102683660046131a0565b610d23565b61022661027b3660046131a0565b610d4a565b61029361028e366004613405565b610d6c565b60408051825181526020808401519082015291810151908201526060016101e7565b6102266102c33660046134a1565b61115e565b6102266102d63660046134cf565b611235565b6102266102e9366004613525565b6114e1565b6103016102fc366004613570565b6115c9565b6040805194855260208501939093529183015260608201526080016101e7565b61033461032f3660046134a1565b61172b565b604080519283526020830191909152016101e7565b61035c61035736600461358d565b61198d565b6040516001600160a01b0390911681526020016101e7565b6102036103823660046131a0565b6119ac565b61039a6103953660046135af565b6119d7565b604080519283526001600160a01b039091166020830152016101e7565b61024c600081565b6102266103cd366004613570565b611b13565b6102266103e03660046135db565b611be2565b6101a56103f3366004613334565b611e0a565b61024c610406366004613334565b611fdd565b6102266104193660046131a0565b611ff4565b61039a61042c3660046135af565b611ffe565b61022661043f366004613570565b6120d7565b610226610452366004613646565b61216f565b6101a5612208565b61024c60008051602061400683398151915281565b6104a66040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b600260005414156104d25760405162461bcd60e51b81526004016104c9906136aa565b60405180910390fd5b6002600090815580806104e3612412565b925092509250600061057a6040518060a001604052806067815260200161402660679139853386602001518b8b6040516024016105249594939291906137a9565b60408051601f19818403018152908290529161053f916137fb565b6040519081900390206020820180516001600160e01b03166001600160e01b031990921691909117905284516001600160a01b0316906124f5565b90506000818060200190518101906105929190613817565b905060006105ad82600001518760e001518860a0015161251a565b9050836001600160a01b031663120b8e5033846020015184600001518a602001516105d89190613888565b6105e291906138a0565b84602001518a604001516105f69190613888565b85604001518b6060015161060a9190613888565b6040518563ffffffff1660e01b815260040161062994939291906138b7565b600060405180830381600087803b15801561064357600080fd5b505af1158015610657573d6000803e3d6000fd5b5050506020808401516040808b01919091528085015160608b015283518a5290830151908301516106889250613888565b60208089019190915295909501516080870152505060016000555091949350505050565b60006001600160e01b03198216635a05180f60e01b14806106d157506106d18261259c565b92915050565b6106ef600080516020614006833981519152336119ac565b61070b5760405162461bcd60e51b81526004016104c9906138dd565b8584146107495760405162461bcd60e51b815260206004820152600c60248201526b125b9d985b1a590818d85b1b60a21b60448201526064016104c9565b60006107536125d1565b6040516302abf57960e61b815275213abcb130b1b5a83937b3b930b6a932b1b2b4bb32b960511b600482015290915060009081906001600160a01b037f00000000000000000000000080d629cf2d775cb9b97c4a95fe2269e0e8459d3a169063aafd5e409060240160206040518083038186803b1580156107d357600080fd5b505afa1580156107e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080b9190613924565b905060005b60ff81168a1115610b245760008b8b8360ff1681811061083257610832613941565b90506020020160208101906108479190613570565b905060008a8a8460ff1681811061086057610860613941565b6040516313d21cdf60e01b81526001600160a01b038681166004830152602090920293909301359350600092839250908916906313d21cdf9060240160006040518083038186803b1580156108b457600080fd5b505afa1580156108c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108f091908101906139f7565b915091508a6001600160a01b031682608001516001600160a01b03161461094f5760405162461bcd60e51b8152602060048201526013602482015272086ded8d8c2e8cae4c2d840dad2e6dac2e8c6d606b1b60448201526064016104c9565b600061095b8585611ffe565b5060405163152a13cd60e31b8152600481018290529091506001600160a01b0386169063a9509e6890602401602060405180830381600087803b1580156109a157600080fd5b505af11580156109b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d99190613abc565b90506000610a166040518060a0016040528060678152602001614026606791398588866020015186306040516024016105249594939291906137a9565b9050600081806020019051810190610a2e9190613817565b905080604001518a610a409190613888565b99506000610a5b82600001518760e001518860a0015161251a565b90508b6001600160a01b031663120b8e508983600001518960200151610a819190613888565b856020015185602001518b60400151610a9a9190613888565b610aa491906138a0565b85604001518b60600151610ab89190613888565b6040518563ffffffff1660e01b8152600401610ad794939291906138b7565b600060405180830381600087803b158015610af157600080fd5b505af1158015610b05573d6000803e3d6000fd5b5050505050505050505050508080610b1c90613ad5565b915050610810565b506040516302abf57960e61b81526a2530b93b34b9aa37b5b2b760a91b60048201526000907f00000000000000000000000080d629cf2d775cb9b97c4a95fe2269e0e8459d3a6001600160a01b03169063aafd5e409060240160206040518083038186803b158015610b9557600080fd5b505afa158015610ba9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcd9190613924565b90506000610cbe6003848a85888c8c604051602401610bf196959493929190613b1e565b60408051601f198184030181529082905291610c0c91613b66565b60408051918290039091206020830180516001600160e01b03166001600160e01b0319909216919091179052516326a966c160e11b81526001600160a01b038b81166004830152881690634d52cd829060240160206040518083038186803b158015610c7757600080fd5b505afa158015610c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610caf9190613924565b6001600160a01b0316906124f5565b9050837f15bc7538235a26bbf90ff27a286d54cc1f91d523cbf888e6a739fd36621ec50d82806020019051810190610cf69190613abc565b604080519182526001600160a01b03871660208301520160405180910390a2505050505050505050505050565b610d2d8282612688565b6000828152600260205260409020610d4590826123fd565b505050565b610d5482826126af565b6000828152600260205260409020610d459082612729565b610d9060405180606001604052806000815260200160008152602001600081525090565b60026000541415610db35760405162461bcd60e51b81526004016104c9906136aa565b600260009081558080610dc4612412565b925092509250600083602001519050610df760405180606001604052806000815260200160008152602001600081525090565b6000610e886040518060a001604052806067815260200161402660679139873388602001518c30604051602401610e329594939291906137a9565b60408051601f198184030181529082905291610e4d916137fb565b6040519081900390206020820180516001600160e01b03166001600160e01b031990921691909117905286516001600160a01b0316906124f5565b905080806020019051810190610e9e9190613817565b9150506000610eba82600001518760e001518860a0015161251a565b9050600081602001518760400151610ed29190613888565b9050600082604001518860600151610eea9190613888565b604051630120b8e560e41b81529091506001600160a01b0387169063120b8e5090610f20903390600090819081906004016138b7565b600060405180830381600087803b158015610f3a57600080fd5b505af1158015610f4e573d6000803e3d6000fd5b50505050610f6d60408051808201909152600081526060602082015290565b866001600160a01b031663ee3b32698e338f6040518463ffffffff1660e01b8152600401610f9d93929190613c02565b600060405180830381600087803b158015610fb757600080fd5b505af1158015610fcb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ff391908101906139f7565b809250819a505050600061108e60405180608001604052806056815260200161408d605691398b84602001518960400151336040516024016110389493929190613c35565b60408051601f198184030181529082905291611053916137fb565b6040519081900390206020820180516001600160e01b03166001600160e01b031990921691909117905283516001600160a01b0316906124f5565b90506000818060200190518101906110a69190613817565b90506000848683602001516110bb91906138a0565b6110c591906138a0565b604051630120b8e560e41b81529091506001600160a01b038b169063120b8e50906110fa90339085908b908b906004016138b7565b600060405180830381600087803b15801561111457600080fd5b505af1158015611128573d6000803e3d6000fd5b5050604080516060810182529b8c52985160208c01525050958801959095525050600160005550929a9950505050505050505050565b611176600080516020614006833981519152336119ac565b6111925760405162461bcd60e51b81526004016104c9906138dd565b600260005414156111b55760405162461bcd60e51b81526004016104c9906136aa565b600260009081556111c46125d1565b6040516338f6c37160e01b81526001600160a01b0385811660048301528481166024830152919250908216906338f6c37190604401600060405180830381600087803b15801561121357600080fd5b505af1158015611227573d6000803e3d6000fd5b505060016000555050505050565b61124d600080516020614006833981519152336119ac565b6112695760405162461bcd60e51b81526004016104c9906138dd565b6002600054141561128c5760405162461bcd60e51b81526004016104c9906136aa565b6002600090815561129b6125d1565b60408051808201909152600080825260208201529091506040805180820190915260008152606060208201526040516302abf57960e61b8152752632b73234b733a932bbb0b93239a932b1b2b4bb32b960511b60048201526000907f00000000000000000000000080d629cf2d775cb9b97c4a95fe2269e0e8459d3a6001600160a01b03169063aafd5e409060240160206040518083038186803b15801561134257600080fd5b505afa158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a9190613924565b905060005b60ff811686111561122757846001600160a01b0316632155162388888460ff168181106113ae576113ae613941565b90506020020160208101906113c39190613570565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160006040518083038186803b15801561140257600080fd5b505afa158015611416573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261143e9190810190613c7b565b9094509250868660ff831681811061145857611458613941565b905060200201602081019061146d9190613570565b6001600160a01b0316634f9b84778486856040518463ffffffff1660e01b815260040161149c93929190613ce2565b600060405180830381600087803b1580156114b657600080fd5b505af11580156114ca573d6000803e3d6000fd5b5050505080806114d990613ad5565b91505061137f565b6114f9600080516020614006833981519152336119ac565b6115155760405162461bcd60e51b81526004016104c9906138dd565b600260005414156115385760405162461bcd60e51b81526004016104c9906136aa565b600260009081556115476125d1565b604051636c924f2f60e01b81526001600160a01b0386811660048301526001600160401b0380871660248401528516604483015291925090821690636c924f2f906064015b600060405180830381600087803b1580156115a657600080fd5b505af11580156115ba573d6000803e3d6000fd5b50506001600055505050505050565b60008060008060006115d96125d1565b6040516313d21cdf60e01b81526001600160a01b0388811660048301529192506000918291908416906313d21cdf9060240160006040518083038186803b15801561162357600080fd5b505afa158015611637573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261165f91908101906139f7565b91509150600081600001516001600160a01b03166317e386468a8585602001516040518463ffffffff1660e01b815260040161169d93929190613d3a565b60206040518083038186803b1580156116b557600080fd5b505afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190613abc565b90506000611704828560e001518660a0015161251a565b805160408201516020928301519690920151909c919b509499509397509295505050505050565b6000806117577f00000000000000000000000080d629cf2d775cb9b97c4a95fe2269e0e8459d3a61273e565b6002600054141561177a5760405162461bcd60e51b81526004016104c9906136aa565b600260009081556117896125d1565b604051632155162360e01b81526001600160a01b03878116600483015291925060009182919084169063215516239060240160006040518083038186803b1580156117d357600080fd5b505afa1580156117e7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261180f9190810190613c7b565b91509150600061185a6004898986600001518760200151876020015160405160240161183f959493929190613d6b565b60408051601f19818403018152908290529161105391613b66565b9050600080828060200190518101906118739190613db2565b604051637d9d518b60e01b81526001600160a01b038d8116600483015292945090925090871690637d9d518b9060240160206040518083038186803b1580156118bb57600080fd5b505afa1580156118cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f39190613abc565b975081611900828a613888565b61190a91906138a0565b6040516340ec3c6160e11b81526001600160a01b038c811660048301528b8116602483015260448201839052919850908716906381d878c290606401600060405180830381600087803b15801561196057600080fd5b505af1158015611974573d6000803e3d6000fd5b5050505050505050505060016000819055509250929050565b60008281526002602052604081206119a590836128ac565b9392505050565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60008060006119e46125d1565b604051632155162360e01b81526001600160a01b03878116600483015291925060009182919084169063215516239060240160006040518083038186803b158015611a2e57600080fd5b505afa158015611a42573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a6a9190810190613c7b565b9150915080600001516001600160a01b0316633ca5578c878460000151856020015185602001516040518563ffffffff1660e01b8152600401611ab09493929190613dd6565b60206040518083038186803b158015611ac857600080fd5b505afa158015611adc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b009190613abc565b9450816020015193505050509250929050565b611b2b600080516020614006833981519152336119ac565b611b475760405162461bcd60e51b81526004016104c9906138dd565b60026000541415611b6a5760405162461bcd60e51b81526004016104c9906136aa565b60026000908155611b796125d1565b60405163a2be10bd60e01b81526001600160a01b0384811660048301529192509082169063a2be10bd906024015b600060405180830381600087803b158015611bc157600080fd5b505af1158015611bd5573d6000803e3d6000fd5b5050600160005550505050565b611bfa600080516020614006833981519152336119ac565b611c165760405162461bcd60e51b81526004016104c9906138dd565b828114611c545760405162461bcd60e51b815260206004820152600c60248201526b125b9d985b1a590818d85b1b60a21b60448201526064016104c9565b6040516302abf57960e61b81527121b7b6b6b4b9b9b4b7b72932b1b2b4bb32b960711b60048201526000907f00000000000000000000000080d629cf2d775cb9b97c4a95fe2269e0e8459d3a6001600160a01b03169063aafd5e409060240160206040518083038186803b158015611ccb57600080fd5b505afa158015611cdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d039190613924565b90506000805b60ff8116861115611dc357600085858360ff16818110611d2b57611d2b613941565b905060200201351115611db157611d8787878360ff16818110611d5057611d50613941565b9050602002016020810190611d659190613570565b86868460ff16818110611d7a57611d7a613941565b90506020020135856128b8565b84848260ff16818110611d9c57611d9c613941565b9050602002013582611dae9190613888565b91505b80611dbb81613ad5565b915050611d09565b506040516001600160a01b038316815281907f47592ec9d9991a137422beab7c67c9dde0899a7b5cc3c7df0812979abf5be8ac9060200160405180910390a2505050505050565b611e3c6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60026000541415611e5f5760405162461bcd60e51b81526004016104c9906136aa565b600260009081558080611e70612412565b9250925092506000611eac60405180608001604052806056815260200161408d6056913960208501516040516105249188918b90602401613e08565b9050600081806020019051810190611ec49190613817565b90506000611edf82600001518760e001518860a0015161251a565b9050836001600160a01b031663120b8e5033836000015185602001518a60200151611f0a9190613888565b611f149190613888565b84602001518a60400151611f289190613888565b85604001518b60600151611f3c9190613888565b6040518563ffffffff1660e01b8152600401611f5b94939291906138b7565b600060405180830381600087803b158015611f7557600080fd5b505af1158015611f89573d6000803e3d6000fd5b5050506020808401516040808b01919091528085015160608b015283518a529083015190830151611fba9250613888565b602080890191909152959095015160808701525050600160005550919392505050565b60008181526002602052604081206106d190612b00565b610d548282612b0a565b600080600061200b6125d1565b604051632155162360e01b81526001600160a01b03878116600483015291925060009182919084169063215516239060240160006040518083038186803b15801561205557600080fd5b505afa158015612069573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120919190810190613c7b565b9150915080600001516001600160a01b031663156b8523878460000151856020015185602001516040518563ffffffff1660e01b8152600401611ab09493929190613dd6565b6120ef600080516020614006833981519152336119ac565b61210b5760405162461bcd60e51b81526004016104c9906138dd565b6002600054141561212e5760405162461bcd60e51b81526004016104c9906136aa565b6002600090815561213d6125d1565b604051636da2b5b160e11b81526001600160a01b0384811660048301529192509082169063db456b6290602401611ba7565b612187600080516020614006833981519152336119ac565b6121a35760405162461bcd60e51b81526004016104c9906138dd565b600260005414156121c65760405162461bcd60e51b81526004016104c9906136aa565b600260009081556121d56125d1565b60405163de3627c760e01b81529091506001600160a01b0382169063de3627c79061158c90879087908790600401613e3c565b61223a6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6002600054141561225d5760405162461bcd60e51b81526004016104c9906136aa565b60026000908155808061226e612412565b925092509250600082600001516001600160a01b031663b108ba2c338686602001516040518463ffffffff1660e01b81526004016122ae93929190613d3a565b602060405180830381600087803b1580156122c857600080fd5b505af11580156122dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123009190613abc565b90506000612317828660e001518760a0015161251a565b9050826001600160a01b031663120b8e50338360000151886020015161233d9190613888565b846020015189604001516123519190613888565b85604001518a606001516123659190613888565b6040518563ffffffff1660e01b815260040161238494939291906138b7565b600060405180830381600087803b15801561239e57600080fd5b505af11580156123b2573d6000803e3d6000fd5b5050825188525050604081015160208201516123ce9190613888565b60208088019190915294909401516080860152505060016000555090919050565b6123f98282612b31565b5050565b60006119a5836001600160a01b038416612b9c565b60408051610100810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905260c0840183905260e08401839052845180860190955291845283015290600061246d6125d1565b6040516313d21cdf60e01b81523360048201529091506001600160a01b038216906313d21cdf9060240160006040518083038186803b1580156124af57600080fd5b505afa1580156124c3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124eb91908101906139f7565b9094909350909150565b60606119a58383604051806060016040528060278152602001613fdf60279139612beb565b61253e60405180606001604052806000815260200160008152602001600081525090565b83612548576119a5565b600061255d856001600160401b038616612cbf565b9050612572816001600160401b038516612cbf565b6020830181905261258390826138a0565b604083015261259281866138a0565b8252509392505050565b60006001600160e01b03198216637965db0b60e01b14806106d157506301ffc9a760e01b6001600160e01b03198316146106d1565b6040516302abf57960e61b8152742632b73234b733a9ba37b930b3b2a6b0b730b3b2b960591b60048201526000907f00000000000000000000000080d629cf2d775cb9b97c4a95fe2269e0e8459d3a6001600160a01b03169063aafd5e409060240160206040518083038186803b15801561264b57600080fd5b505afa15801561265f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126839190613924565b905090565b600082815260016020819052604090912001546126a58133612cde565b610d458383612b31565b6001600160a01b038116331461271f5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016104c9565b6123f98282612d42565b60006119a5836001600160a01b038416612da9565b6040516302abf57960e61b815270466163746f727956657273696f6e696e6760781b60048201526000906001600160a01b0383169063aafd5e409060240160206040518083038186803b15801561279457600080fd5b505afa1580156127a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127cc9190613924565b604051636d2721a360e11b81526a506f6f6c466163746f727960a81b60048201529091506000906001600160a01b0383169063da4e43469060240160206040518083038186803b15801561281f57600080fd5b505afa158015612833573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128579190613ec5565b905061287282826a506f6f6c466163746f727960a81b612e9c565b610d455760405162461bcd60e51b815260206004820152600b60248201526a139bdd08185b1b1bddd95960aa1b60448201526064016104c9565b60006119a58383612f8a565b60006128c26125d1565b6040516313d21cdf60e01b81526001600160a01b0386811660048301529192506000918291908416906313d21cdf9060240160006040518083038186803b15801561290c57600080fd5b505afa158015612920573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261294891908101906139f7565b9150915060006129588787611ffe565b5060405163152a13cd60e31b8152600481018290529091506001600160a01b0388169063a9509e6890602401602060405180830381600087803b15801561299e57600080fd5b505af11580156129b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129d69190613abc565b90506000612a136040518060a001604052806067815260200161402660679139858a8660200151868b6040516024016105249594939291906137a9565b9050600081806020019051810190612a2b9190613817565b90506000612a4682600001518760e001518860a0015161251a565b9050866001600160a01b031663120b8e508b83600001518960200151612a6c9190613888565b84602001518a60400151612a809190613888565b866020015186604001518c60600151612a999190613888565b612aa391906138a0565b6040518563ffffffff1660e01b8152600401612ac294939291906138b7565b600060405180830381600087803b158015612adc57600080fd5b505af1158015612af0573d6000803e3d6000fd5b5050505050505050505050505050565b60006106d1825490565b60008281526001602081905260409091200154612b278133612cde565b610d458383612d42565b612b3b82826119ac565b6123f95760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b6000818152600183016020526040812054612be3575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106d1565b5060006106d1565b6060833b612c4a5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016104c9565b600080856001600160a01b031685604051612c6591906137fb565b600060405180830381855af49150503d8060008114612ca0576040519150601f19603f3d011682016040523d82523d6000602084013e612ca5565b606091505b5091509150612cb5828286612fb4565b9695505050505050565b6000670de0b6b3a7640000612cd48385613ee8565b6119a59190613f07565b612ce882826119ac565b6123f957612d00816001600160a01b03166014612fed565b612d0b836020612fed565b604051602001612d1c929190613f29565b60408051601f198184030181529082905262461bcd60e51b82526104c991600401613f9e565b612d4c82826119ac565b156123f95760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008181526001830160205260408120548015612e92576000612dcd6001836138a0565b8554909150600090612de1906001906138a0565b9050818114612e46576000866000018281548110612e0157612e01613941565b9060005260206000200154905080876000018481548110612e2457612e24613941565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612e5757612e57613fb1565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106d1565b60009150506106d1565b60008060005b8460ff168260ff161015612f8157604051636839980160e11b81526004810185905260ff821660248201526001600160a01b0387169063d07330029060440160206040518083038186803b158015612ef957600080fd5b505afa925050508015612f29575060408051601f3d908101601f19168201909252612f2691810190613924565b60015b612f3257612f6f565b336001600160a01b0382161415612f4d576001935050612f81565b82612f5781613ad5565b9350508560ff168360ff161415612f6d57600093505b505b80612f7981613ad5565b915050612ea2565b50509392505050565b6000826000018281548110612fa157612fa1613941565b9060005260206000200154905092915050565b60608315612fc35750816119a5565b825115612fd35782518084602001fd5b8160405162461bcd60e51b81526004016104c99190613f9e565b60606000612ffc836002613ee8565b613007906002613888565b6001600160401b0381111561301e5761301e61334d565b6040519080825280601f01601f191660200182016040528015613048576020820181803683370190505b509050600360fc1b8160008151811061306357613063613941565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061309257613092613941565b60200101906001600160f81b031916908160001a90535060006130b6846002613ee8565b6130c1906001613888565b90505b6001811115613139576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106130f5576130f5613941565b1a60f81b82828151811061310b5761310b613941565b60200101906001600160f81b031916908160001a90535060049490941c9361313281613fc7565b90506130c4565b5083156119a55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016104c9565b6001600160a01b038116811461319d57600080fd5b50565b600080604083850312156131b357600080fd5b8235915060208301356131c581613188565b809150509250929050565b6000602082840312156131e257600080fd5b81356001600160e01b0319811681146119a557600080fd5b60008083601f84011261320c57600080fd5b5081356001600160401b0381111561322357600080fd5b6020830191508360208260051b850101111561323e57600080fd5b9250929050565b60008083601f84011261325757600080fd5b5081356001600160401b0381111561326e57600080fd5b60208301915083602082850101111561323e57600080fd5b60008060008060008060006080888a0312156132a157600080fd5b87356001600160401b03808211156132b857600080fd5b6132c48b838c016131fa565b909950975060208a01359150808211156132dd57600080fd5b6132e98b838c016131fa565b909750955060408a013591506132fe82613188565b9093506060890135908082111561331457600080fd5b506133218a828b01613245565b989b979a50959850939692959293505050565b60006020828403121561334657600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156133855761338561334d565b60405290565b60405161010081016001600160401b03811182821017156133855761338561334d565b604051601f8201601f191681016001600160401b03811182821017156133d6576133d661334d565b604052919050565b60006001600160401b038211156133f7576133f761334d565b50601f01601f191660200190565b60008060006060848603121561341a57600080fd5b83356001600160401b0381111561343057600080fd5b8401601f8101861361344157600080fd5b803561345461344f826133de565b6133ae565b81815287602083850101111561346957600080fd5b81602084016020830137600060208383010152809550505050602084013561349081613188565b929592945050506040919091013590565b600080604083850312156134b457600080fd5b82356134bf81613188565b915060208301356131c581613188565b600080602083850312156134e257600080fd5b82356001600160401b038111156134f857600080fd5b613504858286016131fa565b90969095509350505050565b6001600160401b038116811461319d57600080fd5b60008060006060848603121561353a57600080fd5b833561354581613188565b9250602084013561355581613510565b9150604084013561356581613510565b809150509250925092565b60006020828403121561358257600080fd5b81356119a581613188565b600080604083850312156135a057600080fd5b50508035926020909101359150565b600080604083850312156135c257600080fd5b82356135cd81613188565b946020939093013593505050565b600080600080604085870312156135f157600080fd5b84356001600160401b038082111561360857600080fd5b613614888389016131fa565b9096509450602087013591508082111561362d57600080fd5b5061363a878288016131fa565b95989497509550505050565b60008060006040848603121561365b57600080fd5b83356001600160401b038082111561367257600080fd5b61367e87838801613245565b9095509350602086013591508082111561369757600080fd5b5084016040818703121561356557600080fd5b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b80518252602081015160208301526040810151604083015260608101516060830152608081015160018060a01b03808216608085015260a083015191506001600160401b0380831660a08601528160c08501511660c08601528060e08501511660e08601525050505050565b60005b83811015613768578181015183820152602001613750565b83811115613777576000848401525b50505050565b6000815180845261379581602086016020860161374d565b601f01601f19169290920160200192915050565b60006101806137b883896136e1565b6001600160a01b0387811661010085015261012084018290526137dd8285018861377d565b92508561014085015280851661016085015250509695505050505050565b6000825161380d81846020870161374d565b9190910192915050565b60006060828403121561382957600080fd5b604051606081018181106001600160401b038211171561384b5761384b61334d565b80604052508251815260208301516020820152604083015160408201528091505092915050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561389b5761389b613872565b500190565b6000828210156138b2576138b2613872565b500390565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b6020808252601d908201527f53656e646572206d75737420626520746865206d61696e7461696e6572000000604082015260600190565b805161391f81613188565b919050565b60006020828403121561393657600080fd5b81516119a581613188565b634e487b7160e01b600052603260045260246000fd5b805161391f81613510565b60006040828403121561397457600080fd5b61397c613363565b9050815161398981613188565b815260208201516001600160401b038111156139a457600080fd5b8201601f810184136139b557600080fd5b80516139c361344f826133de565b8181528560208385010111156139d857600080fd5b6139e982602083016020860161374d565b602084015250909392505050565b600080828403610120811215613a0c57600080fd5b61010080821215613a1c57600080fd5b613a2461338b565b915084518252602085015160208301526040850151604083015260608501516060830152613a5460808601613914565b6080830152613a6560a08601613957565b60a0830152613a7660c08601613914565b60c0830152613a8760e08601613957565b60e08301528401519092506001600160401b03811115613aa657600080fd5b613ab285828601613962565b9150509250929050565b600060208284031215613ace57600080fd5b5051919050565b600060ff821660ff811415613aec57613aec613872565b60010192915050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0387811682528681166020830152851660408201526060810184905260a060808201819052600090613b5a9083018486613af5565b98975050505050505050565b600080835481600182811c915080831680613b8257607f831692505b6020808410821415613ba257634e487b7160e01b86526022600452602486fd5b818015613bb65760018114613bc757613bf4565b60ff19861689528489019650613bf4565b60008a81526020902060005b86811015613bec5781548b820152908501908301613bd3565b505084890196505b509498975050505050505050565b606081526000613c15606083018661377d565b6001600160a01b0394851660208401529290931660409091015292915050565b6000610160613c4483886136e1565b80610100840152613c578184018761377d565b61012084019590955250506001600160a01b03919091166101409091015292915050565b6000808284036060811215613c8f57600080fd5b6040811215613c9d57600080fd5b50613ca6613363565b8351613cb181613188565b81526020840151613cc181613188565b602082015260408401519092506001600160401b03811115613aa657600080fd5b60808152600060018060a01b038086511660808401526020860151604060a0850152613d1160c085018261377d565b925050808551166020840152806020860151166040840152808416606084015250949350505050565b6001600160a01b03841681526000610140613d5860208401866136e1565b80610120840152612cb58184018561377d565b6001600160a01b038681168252858116602083015284811660408301528316606082015260a060808201819052600090613da79083018461377d565b979650505050505050565b60008060408385031215613dc557600080fd5b505080516020909101519092909150565b8481526001600160a01b03848116602083015283166040820152608060608201819052600090612cb59083018461377d565b6000610140613e1783876136e1565b80610100840152613e2a8184018661377d565b91505082610120830152949350505050565b604081526000613e50604083018587613af5565b82810360208401528335613e6381613188565b6001600160a01b03168152602084013536859003601e19018112613e8657600080fd5b840180356001600160401b03811115613e9e57600080fd5b803603861315613ead57600080fd5b60406020840152613b5a604084018260208501613af5565b600060208284031215613ed757600080fd5b815160ff811681146119a557600080fd5b6000816000190483118215151615613f0257613f02613872565b500290565b600082613f2457634e487b7160e01b600052601260045260246000fd5b500490565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351613f6181601785016020880161374d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351613f9281602884016020880161374d565b01602801949350505050565b6020815260006119a5602083018461377d565b634e487b7160e01b600052603160045260246000fd5b600081613fd657613fd6613872565b50600019019056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564126303c860ea810f85e857ad8768056e2eebc24b7796655ff3107e4af18e3f1e77697468647261772828627974657333322c75696e743235362c75696e743235362c75696e743235362c616464726573732c75696e7436342c616464726573732c75696e743634292c616464726573732c62797465732c75696e743235362c61646472657373296465706f7369742828627974657333322c75696e743235362c75696e743235362c75696e743235362c616464726573732c75696e7436342c616464726573732c75696e743634292c62797465732c75696e7432353629a264697066735822122010722fde9ac9aa3a36d3a34f8e4eedb756ee05f4c3ee6cb32d8b2692ed1a3c4764736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000080d629cf2d775cb9b97c4a95fe2269e0e8459d3a000000000000000000000000b5c54f57d7f3ec6367db4fb5a08a1174797e221c000000000000000000000000d874e1b9ace88bfaf2d5b9859164ac1001b40303
-----Decoded View---------------
Arg [0] : _finder (address): 0x80d629cf2D775cB9b97c4A95Fe2269e0E8459d3A
Arg [1] : _roles (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000080d629cf2d775cb9b97c4a95fe2269e0e8459d3a
Arg [1] : 000000000000000000000000b5c54f57d7f3ec6367db4fb5a08a1174797e221c
Arg [2] : 000000000000000000000000d874e1b9ace88bfaf2d5b9859164ac1001b40303
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.